向量的值在不应该发生变化的时候发生了变化
Values of a vector are changing when they shouldn't be
作为业余学习练习,我正在从头开始编写游戏引擎。我目前正在实现一个渲染队列,但是负责队列的向量的值不断变化。 (当它应该是 10.0f 时,始终为 -107374176 的相同值)向量 objRID 是 OBJR* 类型,其中 OBJR 是一个包含位置信息的结构,以及一个指向位图的指针。我正在使用的位图库似乎不是罪魁祸首,但可以在以下位置找到它:http://partow.net/programming/bitmap/index.html。
首要异常是 0x1CCCCCCCC 的读取访问冲突。我逐步执行了该程序,发现在第 19 次迭代之后,结构的值在 "rep stos" 的每次迭代中都一个一个地变化。我不知道 "rep stos" 会如何影响看似无关的事物。 (首先对汇编程序没有很好的掌握)除了手头的错误之外,我非常愿意接受建议。
如果有人能解释一下下面的程序集是如何影响向量 objRID 的,我想我以后就能自己解决这个问题了。
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
我不想把整个程序都放在这里,但我相信这样会更容易混淆。
程序结构如下:
#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;
}
rep stosd
是实现 memset 的一种方式。一些编译器会将其内联。
看起来你的编译器正在使用它来初始化堆栈内存,毒物值为 0xCCCCCCCC
,4 * 0x6A
字节。 (注意它前面有一个 mov rdi, rsp
。)我假设这是一个调试版本,因为优化版本不会做那些额外的工作。
The overarching exception is a read access violation of 0x1CCCCCCCC.
看起来你从一个未初始化的对象中读取了一个指针,并且 "poison" 值完成了创建一个指针值的工作,你可以很容易地看到它是虚假的,并且错误而不是静默地继续直到稍后离实际问题更远的错误。
指针高半部分的0x00000001
可疑。也许你部分覆盖了这个对象?在存放指针值的内存上设置观察点,找出else修改了什么
或者 您在局部变量超出范围后保留指向局部变量的指针,然后下一个函数调用会重用该堆栈内存作为其堆栈帧。调试模式代码毒化了它的整个堆栈框架,覆盖了你的 std::vector<OBJR*> objRID;
.
指向的一些对象
所以不是矢量内容或矢量对象本身发生了变化,而是矢量内容指向的对象。
同样,0xCCCCCCCC 毒药会在您的程序中查找错误。
(@molbdnilo 发现了这一点。我第一次没有花时间仔细阅读你的整个 C++ 代码。)
作为业余学习练习,我正在从头开始编写游戏引擎。我目前正在实现一个渲染队列,但是负责队列的向量的值不断变化。 (当它应该是 10.0f 时,始终为 -107374176 的相同值)向量 objRID 是 OBJR* 类型,其中 OBJR 是一个包含位置信息的结构,以及一个指向位图的指针。我正在使用的位图库似乎不是罪魁祸首,但可以在以下位置找到它:http://partow.net/programming/bitmap/index.html。
首要异常是 0x1CCCCCCCC 的读取访问冲突。我逐步执行了该程序,发现在第 19 次迭代之后,结构的值在 "rep stos" 的每次迭代中都一个一个地变化。我不知道 "rep stos" 会如何影响看似无关的事物。 (首先对汇编程序没有很好的掌握)除了手头的错误之外,我非常愿意接受建议。
如果有人能解释一下下面的程序集是如何影响向量 objRID 的,我想我以后就能自己解决这个问题了。
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
我不想把整个程序都放在这里,但我相信这样会更容易混淆。
程序结构如下:
#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;
}
rep stosd
是实现 memset 的一种方式。一些编译器会将其内联。
看起来你的编译器正在使用它来初始化堆栈内存,毒物值为 0xCCCCCCCC
,4 * 0x6A
字节。 (注意它前面有一个 mov rdi, rsp
。)我假设这是一个调试版本,因为优化版本不会做那些额外的工作。
The overarching exception is a read access violation of 0x1CCCCCCCC.
看起来你从一个未初始化的对象中读取了一个指针,并且 "poison" 值完成了创建一个指针值的工作,你可以很容易地看到它是虚假的,并且错误而不是静默地继续直到稍后离实际问题更远的错误。
指针高半部分的0x00000001
可疑。也许你部分覆盖了这个对象?在存放指针值的内存上设置观察点,找出else修改了什么
或者 您在局部变量超出范围后保留指向局部变量的指针,然后下一个函数调用会重用该堆栈内存作为其堆栈帧。调试模式代码毒化了它的整个堆栈框架,覆盖了你的 std::vector<OBJR*> objRID;
.
所以不是矢量内容或矢量对象本身发生了变化,而是矢量内容指向的对象。
同样,0xCCCCCCCC 毒药会在您的程序中查找错误。
(@molbdnilo 发现了这一点。我第一次没有花时间仔细阅读你的整个 C++ 代码。)