2013-07-08 8 views
9

u_fgetfileから返されたハンドルをfseek/fread関数に渡そうとしています。ICU u_fgetfileはVS2012のリリースビルドでランタイムと互換性がありません

デバッグランタイムライブラリ(/ MTdに/ MDD)で自分のアプリケーションをリンクするとき何クラッシュがありませんが、私は、静的なバージョンのこの単純なコードがクラッシュに対してリンクする場合:

#include <stdio.h> 
#include "unicode\ustdio.h" 

int main() 
{ 
    UFILE* file; 
    file = u_fopen("C:\\test.txt","r",NULL,"UTF-8"); 
    fseek(u_fgetfile(file),3,SEEK_SET); 
} 

今これは、両方の公式で発生ICUのビルド、およびVisual Studio 2012でカスタムビルドをビルドするとき(デバッグまたはリリースでICUを作成することは重要ではありません)。

私が知った唯一の事は、FILE構造にいくつかの不一致があるようですが、私は本当に分かりません。

編集:

この質問への報奨金を追加することの一環として、ここではソースとバイナリとし、ICU(コード上の掲載と同じ)再生プログラムの両方を含む完全に機能VS2012のプロジェクトです。 http://goo.gl/urTuU

+0

これをテストしましたが、完全性のためだけです: 'u_fopen( ) 'と' u_fgetfile() 'は' NULL'を返しません、そうではありませんか? – alk

+0

私はそれをテストしました。これはFILE構造のためのicuと私のプログラムとの間の何らかの構造不一致のようです。 – monoceres

+0

'FILE'は' 'で定義されています。両方のビルド(libicu **と** test app)で同じでなければなりません。 32ビットと64ビットのビルドが混在していないことを確認してください。 – alk

答えて

4

問題は「icuio51.dll」(リリース)は、静的CRTとリンクしています。したがって、同じ共有CRTのFILEポインタを共有しません!そして、それは「ロック」でクラッシュした理由...

that's一方:'icuio51d.dll'(デバッグ)同じ共有CRT(msvcr110d.dll)に対してリンクおよびそのありさ同じ共有FILE *ポインタを使用します。

「デバッグ」では動作しているが、「リリース」では動作していないためです。

解決方法:「共有CRT」(/ MDおよび/ MDd)を常に使用するための正しい設定でICUを再コンパイルする必要があります。 これを行うには、あなたがfollwoingの手順を行う必要があります。

  1. オープンソリューション "allinone \ allinone.sln"
  2. 編集プロジェクトのプロパティ "IO"
  3. 変更「C/C++ |コード生成|マルチスレッド(/ MT) "を "マルチスレッドDLL(/ MD)「から" ランタイムライブラリのWin32 "プラットフォーム" のために"(x64のが正しいように思える!)
  4. プロジェクト
を再コンパイル
+0

うわー、どれくらいシンプルになったのか信じられない!本当にありがとう! – monoceres

+0

そして、 "私が見逃している非常に明白な解決策"があります; D良い考え –

+0

@monoceres:賞金ありがとう;) –

0

最初の質問:実際に何が起こっているのかを分析するツールが増えるため、C++ 11の機能をコンパイルして使用できますか? 2つの異なるファイルのためとの両方のために、あなたのu_fopenによって

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

int main() 
{ 
    unsigned int size = sizeof(FILE); 
    FILE* file = fopen("main.c", "r"); 
    unsigned int i = 0; 
    unsigned char buffer[size]; 
    memcpy(buffer, file, size); 
    printf("The %u bytes at address %p are: \n", size, file); 
    for (i = 0; i < size; ++i) { 
     printf("%02X ", (unsigned int)(buffer[i])); 
     if ((i+1)%64 == 0) { 
      printf("\n"); 
     } 
    } 
    printf("\n"); 
    fclose(file); 
    return 0; 
} 

があなたのUFILEfopen機能によってFILEを置き換える:

最初のものは、この種のコードを使用して、ファイル構造の中を見しようとするだろうデバッグと静的ライブラリ。

ファイル構造のバイト数が表示され、問題がどこにあるのかについてわかりやすく説明します。

3

問題は、間違ったライブラリとのリンクが原因です。

公式ICUとVS2010 - リリースビルドの逆の結果を正確に再現しましたが、デバッグビルドはクラッシュします。

問題は、VCランタイムのデバッグとリリースの両方をリンクし、異なるバージョンの関数間でFILEポインターを渡すことです(IMHO)。リリースのfopenの結果は、デバッグのfseekに渡されます。 _iobファイルとFILEXファイル(異なる_IOB_ENTRIES)を区別する部分では互換性がないようです。

DebugプロジェクトとRelease ICUをリンクすると、この問題が発生します。

+0

これは理にかなっており、私が信じているのも(d)です。しかし、私はちょうど次の試み:1)清潔なソリューション。 2)リリースモードでICUを構築しました。 3)リリースモードで私のアプリケーションをビルドし、icuuc.libとicuio.libにリンクし、icuuc51.dll、icuio51.dll、icudt51.dll、icuin51.dllを出力ディレクトリにコピーしました。 4)クラッシュはまだ残っています:( – monoceres

+0

システムライブラリとしてインストールすることを目指して、機能の名前を変更せずにICUを構築する方法についての説明があります。 – bbonev

+1

ありがとう、これは私の問題を解決しました。公式ビルドにはリリース用バイナリが含まれています。デバッグ用のバイナリも含まれている次のビルドを使用しました:http ://www.npcglib.org/~stathis/blog/precompiled-icu/ – user502144

8

それが言うところ問題は_lock_file内にあるように私には思える:

/* 
    * The way the FILE (pointed to by pf) is locked depends on whether 
    * it is part of _iob[] or not 
    */ 
    if ((pf >= _iob) && (pf <= (&_iob[_IOB_ENTRIES-1]))) 
    { 
     /* 
     * FILE lies in _iob[] so the lock lies in _locktable[]. 
     */ 
     _lock(_STREAM_LOCKS + (int)(pf - _iob)); 
     /* We set _IOLOCKED to indicate we locked the stream */ 
     pf->_flag |= _IOLOCKED; 
    } 
    else 
     /* 
     * Not part of _iob[]. Therefore, *pf is a _FILEX and the 
     * lock field of the struct is an initialized critical 
     * section. 
     */ 
     EnterCriticalSection(&(((_FILEX *)pf)->lock)); 

「正常な」AはFILE*がトップの枝に入り、u_fgetfileから返されたポインタは、下の枝を入力します。ここでは、_FILEX*であると想定されていますが、これは単に正しくない可能性があります。

ランタイムは、ファイルポインタfb_iobの範囲内にあるかどうかを比較します。しかし、デバッガでは、少なくともリリースビルドではそれがはるかに遠いことがわかります。

u_fgetfileがちょうどUFILE構造内に格納されていたFILE*を返すことを考えると、我々はFILE*が最初の場所で私たちの構造で終わるかを確認するためにufile.cfinit_ownerを検査することができます。このコードを読んだら、リリースビルドでは、_iob配列の2つの別々のインスタンスがCRTに存在すると仮定しなければならないが、デバッグビルドでは1つのインスタンスしか存在しない。

この問題を回避するには、FILE*がメインアプリケーションと同じスレッドで作成されていることを確認する必要があります。これを行うには、あなたはそうのように、u_finitを利用することができます。この後に来たあなたの問題について

FILE* filePointer = fopen("test.txt","r"); 
UFILE* file = u_finit(filePointer,NULL,"UTF-8"); 

fseek(filePointer,3,SEEK_SET); // <- won't crash 

、それがために失敗しただけで、ライブラリ間FILE*を共有している根本的な問題のように私には思えます彼らはFILE*のための別の記憶領域を持っています。私はこれを幾分混乱させることがわかりましたが、私は関与しているコンポーネント(そしてWindows Cランタイムコードのスタイルはどちらも役に立ちません)の必要な理解を持っていません。

したがって、FILE*がICUに割り当てられている場合は、メインアプリケーションでロックすることはできず、その逆もありません(読み取りまたはシークを試みると常にロックが必要になります)。

私が紛失しているこの問題に対する非常に明白な解決策がない限り、あなたのメインアプリケーションでu_fgets()(またはその他の必要なもの)の動作をエミュレートすることをお勧めします。
私が言うことができるものから 、u_fgets()はちょうどUChar*に読み出したデータを変換するには、(あなたがu_fgetConverter()で取得することができます)UFILEに保存されているコンバータと、ファイルからデータを読み取るためにfread()を呼び出し、ucnv_toUnicode()を使用しています。

動作するように見える1つの方法は、静的にICUをリンクすることです。私はそれがあなたのためのオプションであるかどうかわかりませんが、それは私の最後に問題を解決するようです。

ICU(51.2)の最新リリースをダウンロードし、this helpful scriptでコンパイルしました。私はその後icu-release-static-win32-vs2012sicuuc.libsicuio.libsicudt.libsicuin.libとのリンク)の図書館とプロジェクトをリンクしました。

今すぐu_fgets()は、アクセス違反を引き起こさなくなりました。もちろん、今私の.exeはほぼ23 MBの大きさです。

+0

これはありがとうございます!fseekのラインは今や最終的にはクラッシュしません!しかし、私は今、u_finitまたはu_fadoptのUFILE *ハンドルを使用して、 ( – monoceres

+0

@monoceres:Ouch。私は 'FILE *'が有効かどうかを調べるために 'fread'しようとしましたが、それは半分の話でした:)私は見ていきます今晩、私が何を見るか見つけることができます。 –

+0

ええと、icuのリリースビルドのデバッグ情報を追加しただけで、EnterCriticalSectionのelseブランチでu_fgetsがクラッシュすることを確認できます。 – monoceres

関連する問題