Можно только записать Char * в буфер LPVOID? - PullRequest
0 голосов
/ 21 марта 2020

Итак, у меня есть объект сопоставления файлов (это 64 КБ) и представление этого сопоставления (оно также 64 КБ со смещением 0).

Когда я записываю в представление, я сначала записываю длину данные для записи, затем я записываю данные (чтобы я мог прочитать данные, сначала прочитав длину, а затем прочитав это количество байтов)

По какой-то причине этот код работает только при записи в смещения до 16KB (смещение 16383 работает, 16384 я получаю нарушение памяти).

Вот код:

LIB_EXPORT bool mem_write_to_view(mem_mapview_p view, DWORD offset, unsigned char *bytes, int len)
{
    __try
    {
        ((LPDWORD)(view->data))[offset] = len; // access violation only on this line; if I remove this line, it will write all the way up to 64KB
        int sizeOfLen = sizeof(DWORD) / sizeof(char);
        for (int i = 0; i < len; i++)
        {
            ((char *)(view->data))[i + offset + sizeOfLen] = bytes[i];
        }
    }
    __except (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_EXECUTION)
    {
        printf("ERROR: error\r\n");
        report_last(view->reporter, "mem_write_to_view");
        report_last_explicit(view->reporter, "mem_write_to_view", "Failed to write to view.");
        return false;
    }
    return true;
}

Как видно из комментария в коде, я получаю нарушение прав доступа только при попытке установить длину (после 16 КБ, опять же, это работает до 16KB, я не уверен, почему), в противном случае, я могу использовать этот метод для записи до конца представления карты (отсюда и заголовок этого вопроса: «Можно только записать char * в буфер LPVOID»)

view->data инициализируется этой строкой: view->data = MapViewOfFile(map->hMap, FILE_MAP_ALL_ACCESS, offset_hi, offset_lo, size); до вызова mem_write_to_view.

Любая идея, почему это происходит (а также, более конкретно, почему это происходит только при смещениях 16KB +)?

Я запустил VirtualQuery на указателе LPVOID, возвращенном MapViewOfFile, и подтвердил, что он действительно имеет размер 64KB.

Я действительно мало что знаю о низкоуровневом доступе к памяти (я имею в виду, в основном, высокоуровневый объектно-ориентированный фон), поэтому я понятия не имею, какие проблемы я могу вызвать, интерпретируя LPVOID как LPDWORD и затем интерпретировать его как char *, но я почти уверен, что это единственный способ записать длину перед данными, верно?

1 Ответ

1 голос
/ 21 марта 2020

A DWORD составляет 4 байта, а LPDWORD - указатель на DWORD, поэтому арифметика указателя c на нем масштабируется на 4. Поэтому, когда вы делаете:

((LPDWORD)(view->data))[offset] = len;

it масштабирует (умножает) смещение на 4, чтобы получить адрес байта для записи. Это означает, что когда смещение равно 16384, оно записывает 64КБ в блок - что находится за концом.

Что вы, вероятно, хотите это

*(LPDWORD)((char *)view->data + offset) = len;

, чтобы смещение было измеряется в байтах (немасштабировано).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...