2016-06-16 16 views
0

私は、次のようなdll( "so.dll")定義を持っています。C++でdllからインポートされた間違ったオブジェクトの検出と消去

/////// "IOReader.h" ////////////// 
class IOReader 
{ 
public : 
    IOReader() {}; 
    virtual ~IOReader() {}; 
    virtual bool open(const std::string &format, 
    const std::string &fileName, const int mask) = 0; 
    std::string errorMessage; 
}; 
// "IOReader.h" Ends Here 

// ---- so.dll ----/
//////////////// sio.h //////////// 
#ifdef SEIO_EXPORTS 
#define SEIO_API __declspec(dllexport) 
#else 
#define SEIO_API __declspec(dllimport) 
#endif 

#include <string> 
#include "IOReader.h" 

class SReaderIO : public IOReader 
{ 
public: 
    SReaderIO() {}; 
    bool open(const std::string &format, 
    const std::string &fileName, const int mask) 
    { 
    return true; 
    } 
}; 

class TestWrongClass 
{ 
public: 
    TestWrongClass() { }; 
    bool open(const std::string &format, 
    const std::string &fileName, const int mask) 
    { 
    return true; 
    } 
}; 

SEIO_API TestWrongClass* CreateIOReader() 
{ 
    TestWrongClass * module = new TestWrongClass(); 
    return module; 
} 

//// sio.h ends here /////// 

//in the main executable I am loading the dll on run time 
// and after creating a object of type TestWrongClass, 
//I explicitly try to cast it with the wrong object, as follows 

/// Main Source // 
#include <iostream> 
#include <windows.h> 
#include "IOReader.h" 

int main() 
{ 

    HMODULE hDLL=LoadLibrary(L"sIO.dll"); 
    CreateSealafineReaderFn _funcSelafinCreator = NULL; 
    _funcSelafinCreator = (CreateSealafineReaderFn) GetProcAddress (hDLL, 
    "CreateIOReader"); 

    // Method 1 
    void *Iref = (_funcSelafinCreator)(); 
    IOReader * locReader = NULL; 
    locReader = reinterpret_cast <IOReader *>(Iref); // but how to check 
        // that object locReader is not of base type IOReader 
        // so that I may call delete Iref 
    // If I try to do as follow, then I get illegal error from compiler 
    // locReader = dynamic_cast <IOReader *>(Iref); // illegal 

    // Method 2 
    try 
    { 
    locReader = dynamic_cast <IOReader *>((_funcSelafinCreator)()); 
    // works but how can I check wrong casting and catch exception 
    } catch (std::bast_cast) 
    { 
    // how to clear the object created by CreateIOReader 
    } 
} 

// 

私はこのプロセスを行う理由は、メインプログラムがDLLディレクトリ からスキャンされるすべてのDLLは、同じ名前のメソッドを持つことが可能かどうかを確認することです、しかし作成のポインタ型を返しますその方法による対象物は異なることがあり、これは望ましくない。 (上記の場合では、この方法は、CreateIOReaderある)

Iがのdynamic_castを使用する場合、私はbad_cast例外を確認することができ、しかし、オブジェクトが既にDLL内に作成され、Iため、解放されません dllの内部コードにアクセスできない

私がreintepret_castを使って与えた上記のメソッドは動作しますが、正しいオブジェクト型が返されるかどうかはチェックできません。 キャストが正しい型でない場合、Irefポインタ "delete Iref"でdeleteを呼び出して、ヒープからオブジェクトをクリアすることができます。

方法CreateIOReaderで間違ったオブジェクトの作成を確認するため、あなたを助けることができない。この問題dynamic_castのために実行可能なソースコード

+0

タイプ 'CreateSealafineReaderFn'はどのように展開されますか? – Smeeheey

+0

@Smeeheeyステートメントを追加するのを忘れていた typedef IOReader *(* CreateSealafineReaderFn)(); justfor int main() – Gourish

答えて

2

からそれを削除する方法はあります。問題は、関数の実際の戻り値の型がわからず、IOReader*のようなふりをしているということです。実際には何か他のもの(つまり、TestWrongClass*)である可能性があります。エイリアシングルールの下では、これは許可されていません。状況に

コントラストこれを:

class IBase { ... }; 
class IOReader : public IBase { ... }; 
class TestWrongClass : public IBase { ... }; 

また、あなたの関数がIBase*を返すことを知っています。 IOReaderTestWrongClassには共通の祖先があり、IBase*のいずれかを参照すると有効です。

返される可能性がないライブラリ関数を呼び出すのは、奇妙な問題です。私は幾分デザインを変更することをお勧めします。あなたは(とりわけ)ことができます:

  1. として統一された階層を作成につき
  2. int(またはenum)が返されているかを決定するために信頼性の高い方法となりstd::pair<int, void*>、のようなコールリターンの何かを持っている上、あなたは削除の問題に対処するために、その後、アプローチ1を選択した場合は、void*

reinterpret_castことができた後、あなたはIBaseインターフェイスにdestroy()のような機能を追加することができ、そのライブラリによってオブジェクトが削除されます(注:外部ライブラリから与えられたオブジェクトは自分自身には悪い考えです)。

アプローチ2を選択すると、void destroy(int, void*)のようなライブラリ関数を持つことができます。これは、あなたが望む以外のものを受け取った場合にstd::pairのメンバーに渡すことができます。ライブラリはこれらを使用してvoid*を正しいものにキャストして内部的に削除することができます。

関連する問題