1

Windows の LoadLibrary で奇妙な問題が発生しています。最初にいくつかの背景。このアプリケーションは Qt に依存しており、Qt はいくつかのライブラリに分割されています。Qt のバージョンをアップグレードしようとしていますが、誰にも影響を与えることはありません。新しい Qt ライブラリは、古いものと下位互換性があります。つまり、古いバージョンでビルドされたアプリケーションは、新しいバージョンをロードすると実行できます。その逆は当てはまりません。新しいバージョンでビルドされたアプリケーションは、古いバージョンが読み込まれると、シンボルが失われます。

Qt DLL はバージョン固有のディレクトリにあります (例としてc:\qt\qt-4.5.2\libc:\qt\qt-4.8.1\libなど)。ほとんどの開発者が PATH に持っている共通ディレクトリもあり、これには、使用するすべてのサードパーティ ライブラリの「現在の」バージョンが含まれています ( と呼びますc:\common\lib)。これは、アプリケーションの実行時に通常 Qt ライブラリが見つかる場所です。

新しい Qt バージョンのライブラリを共通の場所に置きましたが、1 つのケースを除いて、すべてが正常に機能しているように見えました。問題のアプリケーションは複数のライブラリに分割されており、そのうちのいくつかは を呼び出すことによってロードされLoadLibrary()ます。これらのランタイム ロード DLL の一部は、Qt ライブラリに依存しています。ロードされた DLL が に依存しQtXml、それ自体が に依存している場合がありQtCoreます。

ここが変なところです。アプリケーションは に依存しQtCore、依存するライブラリをロードしますQtXml。アプリケーションとライブラリは、旧バージョンの Qt とリンクしてビルドされています。このアプリケーションを PATH の common ディレクトリだけで実行すると、新しい Qt バージョンの DLL が common ディレクトリからロードされるため、すべてが機能します。ただし、パスに共通ディレクトリの前に古い Qt バージョンの DLL が保存されているディレクトリが含まれている場合、ランタイム DLL のロードはシンボルの欠落で失敗します。

(この状況は、特定のライブラリ バージョンを使用するように PATH を明示的に設定するスクリプトを使用して、自動化された単体テストを実行するときに発生します。)

私が把握できる限り、アプリケーションは の古いバージョンをロードしてQtCore.dllおり、ランタイムにロードされた DLL は (どういうわけか) の新しいバージョンをQtXml.dllロードQtCoreしています。

しかし、PATH はc:\qt\qt-4.5.2\lib;c:\common\lib(および他の無関係なパス) のようなものであるため、これは不可能に思えます。共通の lib ディレクトリから新しいものを削除するQtXmlと (古いバージョンに置き換えるのではなく、削除するだけです)、LoadLibrary()すべての Qt ライブラリの 4.5.2 バージョンが読み込まれるため、成功します。しかし、PATH (共通) に Qt 固有のバージョン ディレクトリを指定せずに実行すると、QtXml.

これはどうやってできるの?どのようLoadLibrary()に (またはライブラリの依存関係を解決するために再帰的に呼び出すものは何でも)後でライブラリをロードできPATHますか? 共通ライブラリ ディレクトリが特別に考慮されていることを示すものは何も見つかりません (これは設定された DLL ディレクトリではありません)。ビルド プロセスでは言及されていませんが、開発者がPATH便宜上持っているものです。

ところで、同様の状況が Linux と に存在しLD_LIBRARY_PATHdlopen()そこでは問題なく動作します。これは、私には理解できない Windows のやり方の違いです。何がうまくいかないのかについての洞察を持っている人はいますか?

4

1 に答える 1

3

LoadLibrary意外な行動が多い。MSDNのすべてのコメントを完全に理解してください。

同じ名前のライブラリ (任意のバージョン) が既に読み込まれている場合、LoadLibrary は既に読み込まれている DLL へのハンドルを返します。それがあなたのシナリオに影響を与える可能性があります。

次に、相対パスまたはファイル名のみを指定した場合、LoadLibrary は難解な検索ルールを適用します。通常、PATH 変数は最後に検索する場所です。PATH をチェックする前に、他のルールが「間違った」DLL を見つけている可能性があります。検索ルールが間違ったファイルを取得しないように、読み込みたいファイルには常に絶対パスを使用することをお勧めします。一般的なセキュリティ上の欠陥は、LoadLibrary がどこを検索するかを制御しないことであり、攻撃者はアプリケーションに改ざんされた DLL をロードするように仕向けます。

最後に、インストーラーがDLL リダイレクトを適用して、ユーザーが要求した内容とその場所を上書きすることも可能です。これが Qt DLL で一般的かどうかはわかりませんが、レジストリを確認することをお勧めします。

私は時々、SysInternals の ProcMonを使用して、プログラムが DLL をロードしているときにそのプログラムを観察しました。チェックする各場所を確認できます。これにより、間違ったバージョンが検出された理由の手がかりが得られる場合があります。

于 2012-06-19T13:16:45.453 に答える