2012-06-18 9 views
12

Wyobraź masz ah plikówg ++, wymagają łącznik ostrzegawczy/błąd dla wielu szablonu specjalizacji

#include <iostream> 

template<typename T> struct A{ 
    int magic; 
    A():magic(1234){} 
    void f(){std::cout<<"default f"<<magic<<std::endl;} 
}; 


void f(A<int>* a); 

to funkcja f jest określona w "a.cpp"

#include "a.h" 
void f(A<int>* a){ 
    a->f(); 
} 

i wreszcie " main.cpp”specjalizuje się szablon, a następnie używa f

#include "a.h" 
template<> struct A<int>{ 
}; 

int main(){ 
    A<int> a; 
    f(&a); 

} 

Oczywiście kompilator używa non specjalistyczną wersję dla AO, a Specjalna wersja dla main.o, tj. zdarzają się dwie różne implementacje A. Podczas wykonywania, f może drukować tylko śmieci/segfault, ponieważ przekazany obiekt ma inną strukturę niż oczekiwana.

Czy istnieje sposób, aby linker ostrzegł, że istnieją dwie wersje A?

+0

Jest to dość trudny problem do rozwiązania, dlatego nie ma obowiązkowej diagnostyki dla tego. – Flexo

+0

HTH: usuń wszystkie szablony z pytania - a otrzymasz taki sam wynik. Pozostaw tylko deklarację przekazania w a.h struktury A; i przenieś pełną wersję do a.cpp. main.cpp - tylko usunąć szablon ... – PiotrNycz

Odpowiedz

3

Powodem Złoto nie ostrzega o tym, że złoto wykrywa tylko symbol niedopasowania (ten sam symbol jest zdefiniowany w wielu plikach obiektowych w niekompatybilne sposoby), a nie ma takiego niedopasowania w przykładzie.

Uruchamianie przykład pod Valgrind wywołuje ten błąd choć:

valgrind --track-origins=yes ./a.out 

==11004== Memcheck, a memory error detector 
==11004== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==11004== Using Valgrind-3.8.0.SVN and LibVEX; rerun with -h for copyright info 
==11004== Command: ./a.out 
==11004== 
==11004== Conditional jump or move depends on uninitialised value(s) 
==11004== at 0x40B6D24: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40B703C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40C26DE: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib64/libstdc++.so.6.0.16) 
==11004== by 0x40094F: A<int>::f() (a.h:6) 
==11004== by 0x4008CB: f(A<int>*) (a.cpp:3) 
==11004== by 0x400977: main (main.cpp:7) 
==11004== Uninitialised value was created by a stack allocation 
==11004== at 0x400964: main (main.cpp:5) 

należy uzyskać jeszcze lepszy raport z Address Sanitizer:

Aktualizacja:

Chodzi o to, że chciałbym wykryć błąd w czasie łączenia, a nie podczas wykonywania.

rozumiem twój punkt widzenia, ale nie jest to obecnie możliwe dla obu kompilator (nie posiada informacji o innych jednostkach translacji) lub łącznikiem (nie ma informacji na temat typów zaangażowanych), aby ostrzec o tym .

Teraz, dla kompilacji debugowania, łącznik mógłby teoretycznie to zrobić, jeśli dla każdej funkcji także porównał informacje debugowania dla typów parametrów. Proponuję złożenie prośby o dodanie złota w wersji bugzilla.

+1

Dziękuję. Faktycznie dowiedziałem się, że ta sytuacja miała miejsce w moim kodzie przy użyciu valgrind, a następnie wyprowadziłem ten zabawkowy przykład. Chodzi o to, że chciałbym wykryć błąd w czasie łączenia, a nie podczas wykonywania. –

1

Złoto łącznikowa może dać ostrzeżenie z --detect-ODR-naruszeń

Działa poprzez porównanie pliku i numer linii dla każdej definicji szablonu i ostrzeżenia, jeśli nie wszystkie są takie same.

+0

dziękuję, ale ld -version złoto GNU (GNU Binutils dla Ubuntu 2.21.53.20110810) 1,11 i g ++ -o Test main.cpp a.cpp -Wl, --detect-odr-violations -Wall nie daje ostrzeżeń –

+0

Używa informacji debugowania, więc spróbuj dodać -g –

+0

Dziękuję. nadal g ++ -g -c main.cpp g ++ -g -c a.cpp g ++ -o -g Test main.o ao -Wl - Detect-ODR-łamanie -Wall nie daje ostrzeżenia sam dla g ++ -g -o test główny.cpp a.cpp -Wl, - wykrywanie-odr-naruszenia -Wall –

1

Myślę, że odpowiedź brzmi "nie" i pozostanie w ten sposób.

Typy mają tylko nazwy, które linker widzi, gdy pojawiają się w parametrach funkcji lub argumentach szablonu (może być kilka innych dziwnych). Twój przykład jest w rzeczywistości jednym z łatwiejszych przypadków i wykryciu, że linker musiałby pracować z ABI, która (w efekcie) zaznacza argumenty szablonu dostarczane przez specjalizację. Ale nie mogą tego zrobić: musisz mieć możliwość przekazania wskaźnika do szablonowej struktury, nie wiedząc, czy chodzi o specjalizację.

Nawet wtedy nie można uzyskać znacznie bardziej radykalnego niż choćby banalne zmiany ABI, to znaczy przynajmniej rozważenie, czy należy ponownie skompilować i/lub ponownie połączyć każdą bibliotekę i plik wykonywalny.Jeśli twoje konstrukcje były członkami struct trojan { A<int> greeks; }, to i tak miałbyś takie same nazwy typów i gdyby nigdy nie pojawiły się jako parametry funkcji lub argumenty szablonu, linker nigdy by ich nie zobaczył, nawet gdyby były inne.

Aby uzyskać automatyczne wykrywanie, zacznę od przystępnego interfejsu OSS C++, takiego jak clang. Będziesz potrzebować (niestandardowych) reguł mangerowania nazw, które znaczą nazwy argumentów specjalizacyjnych szablonów i sprawiają, że generują listy pasm bocznych wszystkich deklaracji szablonów, do których się odwołuje. Następnie napisz osobne narzędzie, które zajmie się listami wszystkich obiektów, które są ze sobą połączone, i narzeka, jeśli znajdzie używane argumenty nazwa + (nie tylko odwołanie lub deklaracja) w jednym obiekcie, który jest również używany w innym, ale z innej specjalizacji.

Powiązane problemy