2016-05-09 8 views
2

はI」のインタフェースクラスC++クラスライブラリ動的ランタイム割り当て

class foo_if_t { 

}; 

foo_if_tから継承し、次のコードを持つクラスfoo_tと最初のライブラリlibfoo_orig.soを有していると仮定します第2ライブラリlibfoo_mod.soクラスfoo_tは次のように再定義されます。

#include "foo_if.h" 

class foo_t : public foo_if_t{ 
private: 
    int res[100]; 
public: 
    foo_t() { 
     for (int i=0; i<100; i++) 
     res[i] = i; 
    } 
    virtual ~foo_t(){} 
}; 

私はシンボリックリンクlibfoo.so --> libfoo_orig.soを作成し(したがってにlibfoo.soにリンク)g++ -ggdb -O0 test.cpp -o test -L. -lfooで次のアプリケーション

#include "foo_orig.h" 

int main(){ 
    foo_if_t *foo_if = new foo_t(); 
    delete foo_if; 
} 

をコンパイル。

この時点で私はシンボリックリンクをlibfoo_mod.soに変更し、コードを再実行します。これは、次のエラーになります:

*** Error in `./test': free(): invalid next size (fast): 0x0000000001ec9010 *** 
Aborted (core dumped) 

私はそれが起こってできたと考えていることはfoo_mod.sofoo_tコンストラクタである場合は、ライブラリfoo_orig.soからfoo_tのコンストラクタの割り当てはそう、foo_mod.soから1以上のヒープの小さな塊を食べることです呼び出されると、割り当て境界を越えてヒープメモリがダーティになります(したがって、ヒープを破損しますnextチャンク参照)。これは、実際にコンストラクタコードが呼び出されたことに基づいて、実行時に動的に解決されると考えていたのに対し、ヒープの予約はリンク時に何らかの形で事前計算されていると私に伝えています。私は間違っていますか?もしそうでなければ、生成された出力コードはなぜこのように動作していますか?

耐性テストとして、私はstatic foo_it_t * foo_if_t::new_instance()の実装内でnew foo_t()呼び出しを各ライブラリに書きました。メインコードからnew_instanceを呼び出すと正しく動作します。

答えて

2

ここでの問題は、ライブラリコードとメインプログラムコードがfoo_tというレイアウト構造の考え方が異なることです。彼らは両方とも型の存在を認識していますが、どちらもそれを定義する別のバージョンのヘッダーでコンパイルされています。これは常に大きな問題につながるだろう。

場合によっては、newによって実行される実際のメモリ割り当てがメインプログラムからコンパイルされているため、作成されたオブジェクトのサイズがどのようなものかという考えがあります。一方、コンストラクタはライブラリコードでコンパイルされ、基礎となるオブジェクトサイズの考え方はまったく異なります。そのため、メインプログラムはヒープ上にsizeof(foo_t)というオブジェクトを作成します。その内容はsizeof(int)です。これを知らないコンストラクタは、メモリを最大100個のintに奪ってしまい、ヒープを破壊します。

基本的には、このように「不正行為」することはできません。ヘッダーファイルを変更した場合は、このヘッダーに依存するライブラリを再コンパイルするか、このような予期しないトラブルに直面する必要があります(この場合は意図的に実行していますが、これは偶然でも簡単に行うことができます)。