Rilevare il misusage di delete [] vs. delete in fase di compilazione

19

Mi piacerebbe sapere se è possibile rilevare l'errore delete commentato di seguito al momento della compilazione? Soprattutto, mi piacerebbe sapere del compilatore g ++.

ClassTypeA *abc_ptr = new ClassTypeA[100];  
abc_ptr[10].data_ = 1;  
delete abc_ptr; // error, should be delete []  
    
posta SebGR 13.02.2013 - 15:32
fonte

5 risposte

6

In generale, il compilatore non può rilevare tali errori. Esempio: supponiamo che il costruttore di qualche classe assegni un membro di dati usando new TypeName[] , ma il distruttore usa erroneamente delete invece di delete[] . Se il costruttore e il distruttore sono definiti in unità di compilazione separate, come fa il compilatore a sapere quando compila il file che definisce il distruttore che l'uso è incoerente con quello nel file compilato separatamente che definisce il costruttore?

Per quanto riguarda i compilatori GNU, non è così. Come notato sopra, non può farlo nel caso generale. Un compilatore non deve rilevare errori di nuovo / eliminazione non corrispondenti perché si tratta di un comportamento non definito. UB è la carta "esci da prigione gratis" del compilatore.

Strumenti come valgrind possono rilevare e rilevare questo tipo di disallineamenti nuovi / eliminati, ma lo fanno in fase di runtime. Potrebbe esserci uno strumento di analisi statico che analizzi tutti i file sorgente che verranno eventualmente compilati per formare un eseguibile, ma non di uno strumento di analisi statica in grado di rilevare questo tipo di errore.

    
risposta data 13.02.2013 - 17:13
fonte
28

Puoi utilizzare le classi RAII appropriate su delete . Questo è l'unico modo sicuro per farlo, e questo errore è solo uno dei moltissimi che incontrerai chiamando delete te stesso.

Utilizza sempre le classi per gestire le risorse dinamiche del ciclo di vita e il sistema di tipi imporrà la distruzione delle risorse corretta.

Modifica: "Che cosa succede se si sta verificando il codice e non è possibile modificarlo?" Sei fottuto.

    
risposta data 13.02.2013 - 15:35
fonte
10

Questo particolare errore - sì. Questo tipo di errore in generale: sfortunatamente no! Ciò implicherebbe prevedere il flusso di esecuzione senza effettivamente eseguirlo, e ciò non è possibile per i programmi arbitrari. (Ecco perché la maggior parte dei compilatori non tenta nemmeno di rilevare casi semplici come il tuo esempio.)

Quindi la risposta di DeadMG è appropriata: non cercare di farlo correttamente prestando attenzione - l'attenzione umana è fallibile. Usa i mezzi forniti dalla lingua e fai attenzione al computer.

    
risposta data 13.02.2013 - 15:46
fonte
4

Il caso banale che mostri può essere rilevato al momento della compilazione, perché l'istanziazione e la distruzione dell'oggetto sono nello stesso ambito. In generale, la cancellazione non è nello stesso ambito, o anche lo stesso file sorgente, come l'istanziazione. E un tipo di puntatore del C ++ non porta informazioni sul fatto che faccia riferimento a un singolo oggetto del suo tipo o a un array, per non parlare dello schema di allocazione. Quindi non è possibile diagnosticare questo al momento della compilazione in generale.

Perché non diagnosticare casi speciali che sono possibili?

In C ++ esistono già strumenti per gestire la perdita di risorse dinamiche legate agli ambiti, ovvero puntatori intelligenti e matrici di livello superiore ( std::vector ).

Anche se utilizzi il corretto delete flavor, il tuo codice non è ancora sicuro. Se il codice tra new[] e delete[] termina con un'uscita dinamica, la cancellazione non viene mai eseguita.

Per quanto riguarda il rilevamento del tempo di esecuzione, lo strumento Valgrind fa un buon lavoro nel rilevare questo in fase di esecuzione. Guarda:

==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781==    at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048498: main (in /home/kaz/test/a.out)
==26781==  Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048488: main (in /home/kaz/test/a.out)

Ovviamente, Valgrind non funziona su tutte le piattaforme e non è sempre pratico o possibile riprodurre tutte le situazioni di runtime sotto lo strumento.

    
risposta data 13.02.2013 - 17:32
fonte
-3

Alcuni esempi banali di rilevamento al momento della compilazione / analisi statica:

Su un host RHEL7 con cppcheck 1.77 and 1.49

> cat test.cc
#include <memory>
int main(){char* buf = new char[10];delete buf;}

link

> cppcheck -x c++ test.cc
Checking test.cc ...
[test.cc:2]: (error) Mismatching allocation and deallocation: buf

Con clang++ 3.7.1 su RHEL7

> clang++ --analyze -x c++ test.cc
test.cc:2:37: warning: Memory allocated by 'new[]' should be deallocated by
'delete[]', not 'delete'
int main(){char* buf = new char[10];delete buf;}
                                    ^~~~~~~~~~
1 warning generated.

Clang Static Analyzer può anche rilevare quando std::unique_ptr non viene passato <char[]>

> cat test2.cc
#include <memory>
int main(){std::unique_ptr<char> buf(new char[10]);}

link

> clang++ --analyze -x c++ -std=c++11 test2.cc
In file included from test2.cc:1:
In file included from /opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/memory:81:
/opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/bits/unique_ptr.h:76:2: 
warning: Memory allocated by
      'new[]' should be deallocated by 'delete[]', not 'delete'
        delete __ptr;
        ^~~~~~~~~~~~
1 warning generated.

Aggiornamento in basso con un link al lavoro che ha aggiunto questo a clang, i test e un bug che ho trovato.

Questo è stato aggiunto a clang con reviews.llvm.org/D4661 - "Rileva disallineamento" nuovo "e" elimina "utilizza" .

I test sono in prova / Analisi / MismatchedDeallocator-checker-test.mm

Ho trovato questo bug aperto - bugs.llvm.org/show_bug.cgi?id=24819

    
risposta data 01.03.2017 - 01:25
fonte

Leggi altre domande sui tag