2012-06-18 34 views
12

Hãy tưởng tượng bạn có một tập tin ahg ++, đòi hỏi mối liên kết cảnh báo/lỗi cho nhiều mẫu chuyên môn

#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); 

thì hàm f được định nghĩa trong "a.cpp"

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

và cuối cùng, " main.cpp "chuyên về mẫu và sau đó sử dụng f

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

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

} 

Rõ ràng trình biên dịch sử dụng phiên bản không dành riêng cho ao và phiên bản chuyên biệt cho main.o, tức là có hai sự triển khai khác nhau của A. Khi thực hiện, f chỉ có thể in rác/segfault, bởi vì đối tượng được truyền có cấu trúc khác với cấu trúc mong đợi.

Có cách nào để làm cho trình liên kết cảnh báo rằng có hai phiên bản A không?

+0

Đó là một vấn đề khá khó giải quyết, đó là lý do tại sao không có chẩn đoán bắt buộc cho việc này. – Flexo

+0

HTH: xóa tất cả các mẫu khỏi câu hỏi - và bạn sẽ có kết quả tương tự. Chỉ để lại khai báo chuyển tiếp trong a.h của struct A; và chuyển toàn bộ phiên bản sang a.cpp. main.cpp - chỉ loại bỏ mẫu ... – PiotrNycz

Trả lời

3

Lý do vàng không cảnh báo về điều này là vàng chỉ phát hiện biểu tượng không khớp (cùng biểu tượng được xác định trong nhiều tệp đối tượng theo cách không tương thích) và không có sự không khớp như vậy trong ví dụ.

Chạy ví dụ dưới Valgrind không tạo ra lỗi này mặc dù:

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) 

Bạn sẽ nhận được báo cáo thậm chí tốt hơn từ Address Sanitizer:

Cập nhật:

Vấn đề là tôi muốn để phát hiện lỗi khi liên kết thời gian, không phải trong quá trình thực thi.

Tôi hiểu quan điểm của bạn, nhưng hiện tại không thể cho trình biên dịch (không có thông tin về các đơn vị dịch khác) hoặc trình liên kết (không có thông tin về các loại liên quan) để cảnh báo bạn về điều này .

Bây giờ, đối với bản dựng gỡ lỗi, trình liên kết có thể trong lý thuyết làm điều này, nếu cho mọi chức năng, nó cũng so sánh thông tin gỡ lỗi cho các loại tham số. Tôi khuyên bạn nên gửi yêu cầu tính năng cho vàng trong bugzilla.

+1

Cảm ơn bạn. Tôi thực sự phát hiện ra tình huống này đang xảy ra trong mã của tôi bằng cách sử dụng valgrind, và sau đó tôi lấy ví dụ đồ chơi này. Vấn đề là tôi muốn phát hiện lỗi khi liên kết thời gian, không phải trong quá trình thực thi. –

1

Các mối liên kết vàng có thể cung cấp một cảnh báo với --detect-ODR-vi phạm

Nó hoạt động bằng cách so sánh các tập tin và số dòng cho mỗi mẫu định nghĩa và cảnh báo nếu họ là không phải tất cả giống nhau.

+0

cảm ơn bạn, nhưng ld -version GNU vàng (GNU binutils cho Ubuntu 2.21.53.20110810) 1.11 và g ++ -o test main.cpp a.cpp -Wl, --detect-odr-vi phạm -Wall không có cảnh báo –

+0

Nó sử dụng thông tin gỡ lỗi để thử thêm -g –

+0

Cảm ơn bạn. vẫn là g ++ -g -c main.cpp g ++ -g -c a.cpp g ++ -g -o kiểm tra chính.o ao -Wl, - phát hiện-odr-vi phạm -Wall không có cảnh báo tương tự cho g ++ -g -o kiểm tra main.cpp a.cpp -Wl, - phát hiện-odr-vi phạm -Wall –

1

Tôi nghĩ câu trả lời là "không" và nó sẽ tiếp tục như vậy.

Loại chỉ có tên mà trình liên kết nhìn thấy khi chúng xuất hiện trong tham số hàm hoặc đối số mẫu (một số oddballs khác? Có thể). Ví dụ của bạn thực sự là một trong những trường hợp dễ dàng hơn, và để phát hiện rằng trình liên kết sẽ phải làm việc với một ABI (có hiệu lực) đánh dấu các đối số mẫu được cung cấp bởi một chuyên môn. Nhưng họ không thể làm điều đó: bạn phải có khả năng truyền một con trỏ tới một cấu trúc có khuôn mẫu mà không biết liệu nó có trỏ đến một chuyên môn hay không. Thậm chí sau đó, bạn không thể nhận được nhiều hơn triệt để hơn cả những thay đổi ABI tầm thường, nó có nghĩa là ít nhất là xem xét liệu bạn cần phải biên dịch lại và/hoặc liên kết lại mọi thư viện và thực thi được hay không.Nếu cấu trúc của bạn là thành viên struct trojan { A<int> greeks; } thì bạn vẫn có tên kiểu giống hệt nhau và nếu chúng không bao giờ xuất hiện dưới dạng tham số hàm hoặc đối số mẫu thì trình liên kết sẽ không bao giờ thấy chúng ngay cả khi chúng khác nhau.

Để phát hiện tự động, tôi bắt đầu với lối vào OSS C++ có thể tiếp cận giống như tiếng kêu. Bạn sẽ cần các quy tắc mang tên mang tên (không chuẩn) để đánh dấu các tên đối số của template-template và làm cho nó tạo ra các danh sách biên của tất cả các khai báo mẫu mà nó tìm thấy tham chiếu đến. Sau đó viết một công cụ riêng biệt xem xét các danh sách cho tất cả các đối tượng đang được liên kết với nhau và phàn nàn nếu nó tìm thấy tên + đối số được sử dụng (không chỉ được tham chiếu hoặc khai báo) trong một đối tượng cũng được sử dụng trong một đối tượng khác.

Các vấn đề liên quan