【问题标题】:Changing pointer type causes write access exception更改指针类型会导致写访问异常
【发布时间】:2018-09-04 21:50:23
【问题描述】:

我试图弄清楚在缓冲区末尾附近写入一块内存是否会溢出,但我遇到了一个奇怪的问题,我猜这是由于对指针类型如何工作的一些误解。

鉴于这段代码,它只是分配内存并尝试在它的最后写入:

#include <Windows.h>
#include <stdint.h>

int main() {
    size_t size = 19200;
    int16_t* start = (int16_t*) VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    int16_t* end = start + size;
    int16_t* writeToEnd = end - sizeof(int16_t);
    *writeToEnd = 1;

    return 0;
}

我在writeToEnd 收到非法写入异常。但是,如果我将所有内容都更改为 int:

#include <Windows.h>
#include <stdint.h>

int main() {
    size_t size = 19200;
    int* start = (int*) VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    int* end = start + size;
    int* writeToEnd = end - sizeof(int);
    *writeToEnd = 1;

    return 0;
}

一切正常。我会理解某些值是否会导致int16_t-type 溢出,但是通过手动检查所有值,一切似乎都正常。 Visual Studio 内存窗口显示可用内存小于 end 计算的内存。

我误会了什么?不应该pointer + size == endOfBuffer,不管使用什么类型?

【问题讨论】:

    标签: c pointers memory allocation


    【解决方案1】:

    VirtualAlloc 中的第二个参数是要分配的大小,以bytes 为单位。如果你想要一个 19200 个 16 位整数的数组,你应该调用它

    int16_t* start = (int16_t*) VirtualAlloc(0, size*sizeof(int16_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    

    那么下一行就ok了:

    int16_t *end = start + size;
    

    在这里你有效地得到了

    int16_t *end = &start[size];
    

    比开始提前 19200*2 个字节。

    指针算法使用要跳过的元素数,而不是字节数。 int32_t* 加 1 跳过 4 个字节,int16_t* 加 1 跳过 2 个字节。

    我不知道为什么 int 案例对你有用,因为它不应该。

    【讨论】:

    • 很好看。第二个起作用的原因可能是由于 VirtualAlloc() 的页面舍入策略,并且正在登陆同一进程拥有的页面,这比崩溃更糟糕。
    • 谢谢,int-version 的工作真的让我失望了。但是,如果我真的想要一个 19200 字节的缓冲区,我将如何获得实际边界?还有比int16_t start* = (int16_t*)((char*)start + size)更简单的方法吗?
    • 最后一个位置是 char *last = ((char *) start) + size - 1;如果您的目标是在最后一个可用字节处写入一个字节 1,则不应使用比字节宽的任何内容,否则结果将根据计算机的字节序而有所不同(在小字节序架构中 int16_t i=1 将是写为 0x01 0x00,在大端架构上将写为 0x00 0x01)。
    猜你喜欢
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 2014-08-02
    • 2015-09-12
    • 1970-01-01
    相关资源
    最近更新 更多