2

こんにちは。 Windows および Linux 32 ビット アプリケーションで使用するメモリ マップ ファイル キャッシュ プログラムのプロトタイプを作成しようとしています。プロトタイプを実行するたびに、UnMapViewOfFile を呼び出してキャッシュされたメモリ マップ ファイル領域のマップを解除しようとすると、エラー 487 (Error Invalid Address) が発生します。これは、以前のマップされていない領域をマップ解除しようとしたために発生していると考えられます。このエラー メッセージを無視できるかどうか疑問に思っていました。

MapViewOfFile へのすべての呼び出しが次の方法で UnMapViewOfFile と一致するように最善を尽くします。 MapViewOfFile を呼び出すたびに、次のコードを使用します。

std::deque<Range> ranges_type;

std::multimap<char *,Range> mmultimap;

MapPtr = (char*)::MapViewOfFile(hMapping,
                                FILE_MAP_WRITE | FILE_MAP_READ,
                                0, baseoff,
                                mappedlength);
if (MapPtr == 0){
    DWORD lasterr = GetLastError();
    ErrorMessage(lasterr);
}

ranges_type.insert(RangeDeque::value_type(
                       PreviousNCopy,
                       PreviousN,
                       adjustedptr + n,
                       MapPtr,
                       TimeStamp,
                       mappedlength));

mmultimap.insert(RangeMultiMap::value_type(
                     MapPtr,
                     Range(PreviousNCopy,
                           PreviousN,
                           adjustedptr + n,
                           MapPtr,
                           TimeStamp,
                           mappedlength)));

メモリ マップされたファイル領域をマップ解除するたびに、次の抜粋を使用します。

typedef std::multimap<char *,Range>::const_iterator I;
numerased = 0;
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr);
for (I i=b.first; i != b.second; ++i){ 
    std::dequeue<Range>::iterator iter;
    iter = std::lower_bound(ranges_type.begin(),
                            ranges_type.end(),
                            i->second);
    if (iter != ranges_type.end() && !(i->second < *iter)){
        ranges_type.erase(iter);
        numerased++;
    }
}

erasecount = mmultimap.erase(TmpPrevMapPtr);
retval = UnmapViewOfFile(TmpPrevMapPtr);
if (retval == 0){
    DWORD lasterr = GetLastError();
    ErrorMessage(lasterr);
}

クラス Range は次のようになります。

class Range {
public:
    explicit Range(int item){
        mLow = item;
        mHigh = item;
        mPtr  = 0;
        mMapPtr = 0;
        mStamp = 0;
        mMappedLength = 0;
    }
    Range(int low, int high, char* ptr = 0,char* mapptr = 0, int stamp = 0, int currMappedLength = 0){
        mLow = low;
        mHigh = high;
        mPtr  = ptr;
        mMapPtr = mapptr;
        mStamp = stamp;
        mMappedLength = currMappedLength;
    }

    Range(const Range& r):

    bool operator==(const Range& rhs) const{
        return (mLow <= rhs.mLow && mHigh >= rhs.mHigh);
    }
    bool operator<(const Range& rhs) const{
        return mHigh < rhs.mHigh;      
    } 

public:
    int mLow;   
    int mHigh; 
    char* mPtr;
    char* mMapPtr;
    int mStamp;
    int mMappedLength;
}; // class Range 

この投稿を読んでいただきありがとうございます。

4

2 に答える 2

4

以前のマップされていない領域のマップを解除しようとしています

それはバグです、ピリオド。バグを修正することで、エラーを「無視」します。

または、if テストで無視します。Win32 関数は、修正すべきバグがあることを伝えていますが、それが伝えていることを無視したい場合は、もちろん誰もあなたがそうするのを妨げようとはしません。

于 2011-06-17T18:26:36.250 に答える
1

メモリ領域が 2 回アンマップされる根本的なバグを修正する必要があります。結局のところ、これを考慮してください:

  • アドレス 0x42000000 でメモリの領域 (A と呼びます) をマップします。
  • 0x42000000 で A をアンマップします
  • メモリ B の領域を同じアドレス 0x42000000 にマップします
  • 0x42000000 で A を二重にマップ解除します - 今回のみ B がマップ解除されます
  • B にアクセスしようとすると、クラッシュします。

このメモリを二重にアンマップしている場所を見つけて修正する必要があります。そうしないと、このようなことが最終的に発生する可能性があります。エラーを非表示にすると、デバッグがさらに難しくなります。

これで、アカウンティングはデバッグ目的には問題ありませんが、根本的な原因を修正していません。そもそも、メモリ マッピングを適切に追跡していません。投稿したコードのごく一部についてこれ以上コメントすることはできませんが、修正が必要なものとしてマップ/マップ解除するタイミングを決定するコードを確認する必要があります。手遅れになったときにダブルフリーを抑制しようとしないでください。結局のところ、このメモリ マッピングを二重に解放している場合、これはコードがまだマッピングされていると考えていることを意味するのでしょうか? その場合、アクセス後解放の問題の発生を妨げているのは次のとおりです。

  • 0x42000000 のマップ A
  • A を 0x42000000 でアンマップ
  • アクセス A (クラッシュ!)
  • A を 0x42000000 で二重にアンマップしてみてください (クラッシュのため到達できませんでした)

または:

  • アドレス 0x42000000 でメモリの領域 (A と呼びます) をマップします。
  • 0x42000000 で A をアンマップします
  • メモリ B の領域を同じアドレス 0x42000000 にマップします
  • A がまだマップされていると考えて、0x42000000 のメモリにアクセスし、代わりに B にアクセスします。錯乱!または、データ破損の可能性があります。
于 2011-06-17T18:44:47.117 に答える