首页 > 解决方案 > Values of a vector are changing when they shouldn't be

问题描述

I am writing a game engine from scratch as a free-time learning exercise. I am currently implementing a rendering queue, but the values of the vector in charge of the queue keep changing. (always to the same value of -107374176 when it should be 10.0f) The vector objRID is of type OBJR*, where OBJR is a struct containing position information, as well as a pointer to a bitmap. The bitmap library I am using doesn't seem to be the culprit, but it can be found at: http://partow.net/programming/bitmap/index.html.

The overarching exception is a read access violation of 0x1CCCCCCCC. I have stepped through the program and have found that the values of the struct change one by one every iteration of the "rep stos" after the 19th iteration. I have no real Idea as to how the "rep stos" could affect something which is seemingly unrelated. (A don't have a great grasp on assembler in the first place) I am very open to suggestions besides the error at hand.

If someone could explain how the following assembly affects the vector objRID I think I would be able to solve this problem myself in the future.

163: int loop()
164: {
00007FF7AC74D580 40 55                push        rbp  
00007FF7AC74D582 57                   push        rdi  
00007FF7AC74D583 48 81 EC A8 01 00 00 sub         rsp,1A8h  
00007FF7AC74D58A 48 8D 6C 24 20       lea         rbp,[rsp+20h]  
00007FF7AC74D58F 48 8B FC             mov         rdi,rsp  
00007FF7AC74D592 B9 6A 00 00 00       mov         ecx,6Ah  
00007FF7AC74D597 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00007FF7AC74D59C F3 AB                rep stos    dword ptr [rdi] <---- 19th - 26th iteration here

I hate to just throw the whole program in here, but I believe it is much less confusing this way.

The program is structured as such:

#include "stdafx.h"
#include <Windows.h>
#include "bitmap_image.hpp"
#define maxObjects 1024




struct VEC2_f {
    float x, y;

    VEC2_f(float x, float y)
    {
        VEC2_f::x = x;
        VEC2_f::y = y;
    }

    VEC2_f()
    {
        VEC2_f::x = 0.0f;
        VEC2_f::y = 0.0f;
    }
};

struct OBJR {
    VEC2_f pos, vel;
    int ID = -1;
    bitmap_image* Lbmp;

    OBJR(bitmap_image* Lbmp, VEC2_f pos, VEC2_f vel)
    {
        OBJR::Lbmp = Lbmp;
        OBJR::pos = pos;
        OBJR::vel = vel;
    }

    OBJR(bitmap_image* Lbmp, float x, float y, float vx, float vy)
    {
        OBJR::Lbmp = Lbmp;
        OBJR::pos = VEC2_f(x, y);
        OBJR::vel = VEC2_f(vx, vy);
    }

    //if -1 then ID isn't set yet
    int getID()
    {
        return ID;
    }
};



std::vector<OBJR*> objRID;
int IDCOUNTER = 0;
bool running = true;
HWND con;
HDC dc;
COLORREF color;



void objInit(OBJR* Lobj)
{
    if (objRID.size() > maxObjects)
    {
        objRID.pop_back();
        Lobj->ID = maxObjects;          }
    Lobj->ID = IDCOUNTER++;
    objRID.push_back(Lobj);
}

void input()
{

}

void update()
{

}

VEC2_f interpolate(float interpolation, VEC2_f pos, VEC2_f vel)
{
    return VEC2_f(pos.x + (vel.x * interpolation), pos.y + (vel.y * interpolation));
}




void renderBitmap(bitmap_image* Lbmp, VEC2_f Ipos)
{
    unsigned int h, w;
    rgb_t colorT;
    h = Lbmp->height();  <--- Read access violation here
    w = Lbmp->width();

    for (unsigned int y = 0; y < h; y++)
    {
        for (unsigned int x = 0; x < w; x++)
        {
            colorT = Lbmp->get_pixel(x, y);
            color = RGB(colorT.red, colorT.green, colorT.blue);
            SetPixelV(dc, x + Ipos.x, y + Ipos.y, color);
        }
    }
}

void renderOBJR(float interpolation, OBJR* obj)
{
    renderBitmap(obj->Lbmp, interpolate(interpolation, obj->pos, obj->vel));
}


void render(float interpolation)
{
    for (int i = 0; i < objRID.size(); i++)
    {
        renderOBJR(interpolation, objRID[i]);
    }
}


void resizeWindow()
{
    RECT r;
    GetWindowRect(con, &r);
    MoveWindow(con, r.left, r.top, 800, 600, true);
}


int init()
{
    con = GetConsoleWindow();
    dc = GetDC(con);
    resizeWindow(); 
    return 0;
}


int loop()
{  //<--- this is where the disassembly was taken from and is where the Lbmp becomes invalid
    const int TPS = 60;
    const int SKIP_TICKS = 1000 / TPS;
    const int FRAMESKIP = 1;

    DWORD next_tick = GetTickCount();
    float interpolation;
    int loop;

    while (running)
    {
        loop = 0;
        while (GetTickCount() > next_tick && loop < FRAMESKIP)
        {
            input();
            update();

            next_tick += SKIP_TICKS;
            loop++;
        }
        interpolation = float(GetTickCount() + SKIP_TICKS - next_tick) / float(SKIP_TICKS);
        render(interpolation);

    }
    return 0;
}

int deInit()
{

    ReleaseDC(con, dc);
    return 0;
}



void test() 
{
    bitmap_image bitmap = bitmap_image("testBW.bmp");
    VEC2_f pos = VEC2_f(10.f, 10.f);
    VEC2_f vel = VEC2_f();
    OBJR test1 = OBJR(&bitmap, pos, vel);
    objInit(&test1);
    renderBitmap(&bitmap, pos);

}

int main()
{

    init();
    test();
    loop();
    deInit();
    return 0;
}

标签: c++assemblymemory64-bitgame-engine

解决方案


rep stosd是实现 memset 的一种方法。一些编译器会内联它。

看起来您的编译器正在使用它来初始化堆栈内存,其毒性值为0xCCCCCCCC,4 * 0x6A字节。(注意它mov rdi, rsp前面有一个右边。)我假设这是一个调试版本,因为优化的版本不会做额外的工作。

总体异常是 0x1CCCCCCCC 的读取访问冲突。

看起来您从未初始化的对象中读取了一个指针,并且“毒药”值完成了创建一个您可以轻松看到的指针值的工作是虚假的,并且哪些错误而不是默默地继续,直到后来一些错误远离真正的问题.

指针的0x00000001高半部分是可疑的。也许你部分覆盖了这个对象?在存储指针值的内存上设置一个观察点,并找出还有什么修改它。


或者您在局部变量超出范围后保留指向它们的指针,然后下一个函数调用将堆栈内存重用于其堆栈帧。调试模式代码毒化了它的整个栈帧,覆盖了你的std::vector<OBJR*> objRID;.

所以改变的不是向量内容或向量对象本身,而是向量内容指向的对象。

同样,0xCCCCCCCC 毒药正在寻找程序中的错误。

(@molbdnilo 发现了这一点。我第一次没有花时间仔细阅读你的整个 C++ 代码。)


推荐阅读