是否可以忽略 UnMapViewOFFile() 的错误 487 (ERROR_INVALID_ADDRESS)?

发布于 2024-11-16 03:09:42 字数 2885 浏览 4 评论 0原文

下午好,我们正在尝试构建一个供 Windows 和 Linux 32 位应用程序使用的内存映射文件缓存程序的原型。每次运行原型时,当我们尝试调用 UnMapViewOfFile 取消映射缓存内存映射文件区域时,都会收到错误 487(错误地址无效)。我们认为发生这种情况是因为我们尝试取消映射先前未映射的区域。我们想知道是否可以忽略此错误消息。

我们尽力确保对 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 

感谢您阅读这篇文章。

Good afternoon, We are trying to build a prototype of Memory Mapped File Caching program for use by Windows and Linux 32 bit applications. Every time we run the prototype we get an Error 487(Error Invalid Address) when we try call UnMapViewOfFile to unmap a a cached memory mapped file region. We think this is happening because we trying a unmap a previouslu unmapped region. We were wondering if it is possible to ignore this error message.

We try our best to make sure that every call to MapViewOfFile is matched by an UnMapViewOfFile in the following way, Every time we call MapViewOfFile , we use the following code:

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)));

Everytime we unmap a memory mapped file region, we use the following excerpt:

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);
}

The class Range looks like this:

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 

Thank you for reading this post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

落日海湾 2024-11-23 03:09:42

我们尝试取消映射先前未映射的区域

,这是一个错误。您可以通过修复错误来“忽略”该错误。

或者,只需使用 if 测试忽略它即可。 Win32 函数告诉您有一个错误需要修复,但是如果您想忽略它告诉您的内容,当然没有人会阻止您这样做。

we trying a unmap a previouslu unmapped region

That is a bug, period. You "ignore" the error by fixing the bug.

Alternately, just ignore it with an if test. The Win32 function is telling you there's a bug to fix, but if you want to ignore what it's telling you of course nobody is going to prevent you from doing so.

墨洒年华 2024-11-23 03:09:42

您需要修复导致内存区域两次取消映射的潜在错误。毕竟考虑到这一点:

  • 您在地址 0x42000000 处映射了一个内存区域(称之为 A)
  • 您在 0x42000000 处取消了 A
  • 的映射您在同一地址 0x42000000 处映射了内存 B 区域
  • 您在 0x42000000 处双重取消了 A 的映射 - 只是这次 B 未被映射
  • 您尝试访问 B,然后崩溃了。

您需要弄清楚在哪里双重取消映射此内存并修复它,否则最终可能会发生类似的情况。如果隐藏错误,只会使调试变得更加混乱。

现在,您的核算对于调试目的来说是没问题的,但它并没有解决根本原因;你一开始就没有很好地跟踪你的内存映射。不可能对您发布的一小部分代码进行更多评论,但您应该查看决定何时映射/取消映射的代码作为您需要修复的内容;不要在为时已晚时试图抑制双重释放。毕竟,如果您双重释放此内存映射,这是否意味着您的代码认为它仍然被映射?在这种情况下,什么会阻止发生释放后访问问题:

  • 在 0x42000000 处映射 A
  • 在 0x42000000 处取消映射 A
  • 访问 A(崩溃!)
  • 尝试在 0x42000000 处双重取消映射 A(由于崩溃,未达到)

或者:

  • 您映射一个地址 0x42000000 处的内存区域(称为 A)
  • 您在以下位置取消映射 A 0x42000000
  • 您将内存 B 的一个区域映射到同一地址 0x42000000
  • 认为 A 仍然被映射,您访问 0x42000000 处的内存并访问 B。困惑!或者可能数据损坏!

You need to fix the underlying bug that causes the memory region to be unmapped twice. After all consider this:

  • You map a region of memory (call it A) at address 0x42000000
  • You unmap A at 0x42000000
  • You map a region of memory B at the same address 0x42000000
  • You double-unmap A at 0x42000000 - only this time B is unmapped
  • You try to access B, and crash.

You need to figure out where you're double-unmapping this memory and fix it, or something like this can happen eventually. If you hide the error, it'll just make this that much more confusing to debug.

Now, your accounting is fine for debug purposes, but it's not fixing the root cause; you're not keeping good track of your memory mappings in the first place. It's not possible to comment much more on the small portion of code you've posted, but you should be looking at the code that decides when to map/unmap as what you need to fix; don't just try to suppress the double-frees when it's too late. After all, if you're double-freeing this memory mapping, does this mean your code thinks it's still mapped? In which case what's stopping access-after-free problems from occurring:

  • Map A at 0x42000000
  • Unmap A at 0x42000000
  • Access A (crash!)
  • Try to double-unmap A at 0x42000000 (not reached, due to the crash)

Or:

  • You map a region of memory (call it A) at address 0x42000000
  • You unmap A at 0x42000000
  • You map a region of memory B at the same address 0x42000000
  • Thinking A is still mapped, you access memory at 0x42000000 and access B instead. Confusion! Or possibly data corruption!
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文