自定义操作系统调用嵌套数组内成员CDraw函数触发通用保护错误问题
故障排查与修复方案
核心故障原因
- 数组访问逻辑错误:
windows定义为Window* windows[128](元素为Window指针的一维数组),代码中错误以二维数组形式windows[0][openedWindows]访问,直接读写非法内存;子组件数组children存在完全相同的错误,是触发「General Protection Fault」的最直接原因。 - 类型不匹配+对象切片:数组定义为指针类型,但代码直接存入Window/BaseGuiComponent实例,同时
AddComponent方法值传递参数会直接切割子类(Button/Window)的独有成员,后续访问不存在的成员变量直接触发内存访问错误。 - 子组件索引全局共享:
childIndex是全局变量而非BaseGuiComponent的成员变量,所有组件共用同一个子组件计数,添加、遍历子组件时会访问完全不属于当前组件的内存空间。 - 字符串判断逻辑错误:
strcmp函数相等时返回0,现有代码if (strcmp(type,"Window",128))的判断逻辑完全相反,类型匹配时不会执行对应分支,反而会执行错误分支访问不存在的成员(比如Button访问WindowStyle成员)。 - 空指针/未初始化成员风险:按钮绘制逻辑中直接访问
parent->bound和当前对象的bound,若parent为空或bound未初始化,会直接触发非法内存访问。
修复方案
1. 修正窗口数组与相关逻辑
将窗口数组改为存储实例的一维数组,修正所有访问逻辑:
int openedWindows = 0; Window windows[128]; // 改为存储实例的一维数组,不需要指针 int OpenWindow(Window win) { windows[openedWindows] = win; // 去掉错误的[0]前缀 openedWindows++; return openedWindows-1; }; void CloseWindow(int index) { for(int i = index; i < openedWindows-1; i++) { // 修正遍历范围,不用写死127 windows[i] = windows[i+1]; } openedWindows--; }; void CloseAllWindows() { openedWindows = 0; // 不需要逐个重置,直接重置计数即可 }; /*Draw Windows*/ for(int i = 0; i < openedWindows; i++) { windows[i].Update(); // 去掉错误的[0]前缀 }
2. 修正子组件数组与相关逻辑
将childIndex改为类成员变量,数组改为存储实例的一维数组,修正传参与访问逻辑:
// 类定义内部添加成员变量,删除全局childIndex class BaseGuiComponent { // 其他成员... int childIndex = 0; BaseGuiComponent children[128]; // 改为实例数组,不需要指针 } int BaseGuiComponent::AddComponent(BaseGuiComponent baseGuiComponent) { children[childIndex] = baseGuiComponent; // 去掉错误的[0]前缀 childIndex++; return childIndex-1; }; void BaseGuiComponent::RemoveComponent(int index) { for(int i = index; i < childIndex-1; i++) { // 修正遍历范围 children[i] = children[i+1]; } childIndex--; }; void BaseGuiComponent::ClearComponents() { childIndex = 0; // 直接重置计数即可 }; //List components and Update(); void BaseGuiComponent::DrawChildren() { for(int i = 0; i < childIndex; i++) { children[i].Update(); // 去掉错误的[0]前缀 } };
如果需要保留多态特性,可将数组改为存储智能指针/堆分配指针,传递参数改为引用/指针,避免对象切片。
3. 修正绘制逻辑判断
修正strcmp的判断逻辑,添加空指针校验:
void BaseGuiComponent::CDraw() { if (strcmp(type,"Window") == 0) { // 相等时返回0,添加等于0的判断 Draw->DrawWindow(BackColor.GetHexColor(), CPosition.X, CPosition.Y, CSize.Width, CSize.Height, 2, CText, WindowStyle, Draw->GetScreenBounds()); DrawChildren(); } else if (strcmp(type,"Button") == 0) { // 同上修正判断逻辑 // 添加parent非空校验 if (parent == nullptr) return; Draw->FillRect(BackColor.GetHexColor(), CGlobalPosition.X*4, CGlobalPosition.Y, CSize.Width*4, CSize.Height, parent->bound); Draw->PRINTAT(ForeColor.GetHexColor(),CText, CGlobalPosition.X + nabs(CSize.Width - svlen(CText))/2,CGlobalPosition.Y + nabs(CSize.Height-16)/2, bound); } };
内容的提问来源于stack exchange,提问作者IlcIliaDev
相关产品推荐
相关产品推荐

