Можно ли игнорировать ошибку 487 (ERROR_INVALID_ADDRESS) для UnMapViewOFFile ()? - PullRequest
2 голосов
/ 17 июня 2011

Добрый день! Мы пытаемся создать прототип программы кэширования памяти с отображением файлов для использования в 32-битных приложениях Windows и Linux.Каждый раз, когда мы запускаем прототип, мы получаем ошибку 487 (ошибочный адрес ошибки), когда мы пытаемся вызвать UnMapViewOfFile, чтобы отобразить область файла с кэшированной памятью.Мы думаем, что это происходит, потому что мы пытаемся разархивировать ранее не отображенный регион.Нам было интересно, возможно ли игнорировать это сообщение об ошибке.

Мы стараемся, чтобы каждый вызов 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 

Спасибо за чтение этого поста.

Ответы [ 2 ]

4 голосов
/ 17 июня 2011

мы пытаемся удалить ранее не отображенную область

Это ошибка, точка. Вы «игнорируете» ошибку, исправляя ошибку.

С другой стороны, просто игнорируйте его с помощью теста if. Функция Win32 сообщает вам, что есть ошибка, которую нужно исправить, но если вы хотите игнорировать то, что она говорит вам, конечно, никто не помешает вам сделать это.

1 голос
/ 17 июня 2011

Вам необходимо исправить основную ошибку, из-за которой область памяти дважды отображалась. В конце концов учтите это:

  • Вы отображаете область памяти (назовите ее A) по адресу 0x42000000
  • Вы снимаете карту A в 0x42000000
  • Вы отображаете область памяти B по тому же адресу 0x42000000
  • Вы дважды снимаете карту A с 0x42000000 - только на этот раз B не отображается
  • Вы пытаетесь получить доступ к B, и вылетает.

Вам нужно выяснить, где вы дважды распаковываете эту память и исправляете ее, или что-то подобное может произойти в конце концов. Если вы скроете ошибку, это только сделает это более запутанным для отладки.

Теперь ваш учет в порядке отладки, но не устраняет основную причину; Во-первых, вы плохо отслеживаете свои отображения памяти. Невозможно гораздо больше прокомментировать небольшую часть кода, которую вы разместили, но вы должны смотреть на код, который решает, когда отображать / отменять отображение, как то, что вам нужно исправить; не пытайтесь подавить двойное освобождение, когда уже слишком поздно. В конце концов, если вы дважды освобождаете это отображение памяти, означает ли это, что ваш код думает, что он все еще отображается? В таком случае, что мешает появлению проблем с доступом после освобождения:

  • Карта A в 0x42000000
  • Unmap A в 0x42000000
  • Доступ A (сбой!)
  • Попытайтесь дважды отобразить A на 0x42000000 (не достигнуто из-за сбоя)

Или:

  • Вы отображаете область памяти (назовите ее A) по адресу 0x42000000
  • Вы снимаете карту A в 0x42000000
  • Вы отображаете область памяти B по тому же адресу 0x42000000
  • Мышление A все еще отображается, вы получаете доступ к памяти по адресу 0x42000000 и вместо этого получаете доступ к B. Путаница! Или возможно повреждение данных!
...