12

あなたがああファイルを持っていると想像してください

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

次に、関数fは「a.cpp」で定義されます。

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

最後に、「main.cpp」はテンプレートを特殊化し、fを使用します

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

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

}

明らかに、コンパイラはaoに非特殊バージョンを使用し、main.oに特殊バージョンを使用します。つまり、Aの2つの異なる実装があります。渡されたオブジェクトの構造が異なるため、実行時にfはガベージ/セグメンテーション違反のみを出力できます。期待されたものから。

Aには2つのバージョンがあることをリンカに警告させる方法はありますか?

4

3 に答える 3

3

Goldがこれについて警告しない理由は、Goldがシンボルの不一致(複数のオブジェクトファイルで互換性のない方法で定義されている同じシンボル)のみを検出、例ではそのような不一致がないためです。

ただし、Valgrindで例を実行すると、このエラーが発生します。

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)

AddressSanitizerからさらに良いレポートを入手する必要があります。

アップデート:

重要なのは、実行中ではなく、リンク時にエラーを検出したいということです。

私はあなたの主張を理解していますが、現在、コンパイラ(他の変換ユニットに関する情報がない)またはリンカ(関連する型に関する情報がない)のいずれかがこれについて警告することはできません。

さて、デバッグビルドの場合、リンカーは理論的にはこれを行うことができます。すべての関数について、パラメータータイプのデバッグ情報も比較した場合です。bugzillaでゴールドの機能リクエストを提出することをお勧めします。

于 2012-06-22T05:31:11.020 に答える
1

答えは「いいえ」だと思います。

型には、関数パラメーターまたはテンプレート引数に表示されたときにリンカーが認識する名前しかありません (他のいくつかの奇妙なボール? 多分)。あなたの例は実際にはより簡単なケースの1つであり、リンカーが(実際には)特殊化によって提供されるテンプレート引数をマークするABIを操作する必要があることを検出します。しかし、彼らはそれを行うことができません: 特殊化を指しているかどうかを知らなくても、テンプレート化された構造体へのポインターを渡すことができなければなりません。

それでも、些細な ABI の変更よりも根本的な変更はできません。少なくとも、すべてのライブラリと実行可能ファイルを再コンパイルおよび/または再リンクする必要があるかどうかを検討する必要があります。構造体がメンバーstruct trojan { A<int> greeks; }である場合、とにかく同一の型名を持ち、それらが関数パラメーターまたはテンプレート引数として表示されない場合、それらが異なっていてもリンカーは決してそれらを認識しません。

自動検出を行うには、clang のような親しみやすい OSS C++ フロントエンドから始めます。template-specialization-argument 名をマークし、参照を見つけたすべてのテンプレート宣言のサイドバンド リストを生成する (非標準の) 名前マングリング ルールが必要です。次に、一緒にリンクされているすべてのオブジェクトのリストを調べ、あるオブジェクトで使用されている (参照または宣言されているだけでなく) 名前 + 引数が別のオブジェクトでも使用されているが別の特殊化から使用されている場合に文句を言う別のツールを作成します。

于 2012-06-22T20:32:05.020 に答える
1

ゴールド リンカーは、 --detect-odr-violations で警告を表示する場合があります

各テンプレート定義のファイルと行番号を比較し、それらがすべて同じでない場合は警告することで機能します。

于 2012-06-18T12:02:07.327 に答える