2015-07-30 21 views
8

Così ho questo codice in 2 unità di traduzione distinte:C'è un modo per rilevare le violazioni ODR della funzione inline?

// a.cpp 
#include <stdio.h> 
inline int func() { return 5; } 
int proxy(); 
int main() { printf("%d", func() + proxy()); } 

// b.cpp 
inline int func() { return 6; } 
int proxy() { return func(); } 

Quando compilato normalmente il risultato è 10. Quando compilato con -O3 (inlining on) ottengo 11.

Ho chiaramente eseguito una violazione ODR per func().

Si è presentato quando ho iniziato a unire fonti di dll diverse in meno dll.

ho provato:

  • GCC 5.1 -Wodr (che richiede -flto)
  • linker oro con -detect-odr-violations
  • modificando ASAN_OPTIONS=detect_odr_violation=1 prima di eseguire un binario strumentato con l'indirizzo disinfettante.

Asan può presumibilmente prendere altre violazioni ODR (vars globali con diversi tipi o qualcosa del genere ...)

Questo è un problema veramente brutto C++ e io sono stupito Non c'è attrezzatura affidabile per averlo rilevato.

Forse ho abusato di uno degli strumenti che ho provato? O c'è uno strumento diverso per questo?

EDIT:

Il problema resta inosservato anche quando faccio le 2 implementazioni di func() drasticamente diverso in modo che non vengono compilati per la stessa quantità di istruzioni.

Questo influisce anche sui metodi di classe definiti all'interno del corpo della classe: sono implicitamente incorporati.

// a.cpp 
struct A { int data; A() : data(5){} }; 

// b.cpp 
struct A { int data; A() : data(6){} }; 

Codice precedente con un sacco di copia/incolla + piccole modifiche dopo che è una gioia.

+0

Mi chiedo quale sarebbe il caso d'uso per avere funzioni 'inline' in un file .cpp. Non riesco a pensare a nessun vantaggio possibile. – sjdowling

+1

@sjdowling perché la parola chiave inline? codice legacy. Considerate anche questo: '' 'struct A {A() {}};' '' - qui il costruttore è definito all'interno della definizione struct ed è implicitamente in linea. 2 tali strutture possono avere lo stesso layout ma diversi metodi in linea ... – onqtam

+3

Forse il modo più semplice per trovare queste violazioni ODR in questo codice legacy è rimuovere tutti gli specificatori 'in linea' dalle funzioni definite nei file .cpp ed esaminare eventuali errori di collegamento risultanti. – sjdowling

risposta

3

Il modo più semplice per rilevare tali problemi è quello di copiare tutte le funzioni in una singola unità di compilazione (crearne una temporaneamente se necessario). Ogni compilatore C++ sarà quindi in grado di rilevare e segnalare definizioni duplicate durante la compilazione di quel file.

+1

Questo è il mio attuale modo di risolvere questi problemi, ma non è sempre facile creare un'unità: un sacco di codice legacy + statico anonimo + preprocessore. Anche questo non aiuta con i simboli delle librerie statiche. – onqtam

5

Gli strumenti sono imperfetti.

Penso che il controllo di Gold noterà solo quando i simboli hanno tipi diversi o dimensioni diverse, il che non è vero qui (entrambe le funzioni compileranno allo stesso numero di istruzioni, usando solo un valore immediato diverso).

io non sono sicuro perché -Wodr non funziona qui, ma penso che funziona solo per i tipi, non funzioni, vale a dire rileverà due definizioni contrastanti di un tipo di classe T ma non la vostra func().

Non so nulla del controllo ODR di ASan.