内存访问冲突问题

问题描述 投票:0回答:1

我确实在做一些非法的事情,我想知道是什么。我尽可能地隔离了我的错误。如果我在主函数内部初始化 Items 数组,它不会出现,只有当它存储在 Bottom_Pannel 对象内部时才会出现。

这是代码:

文件主.cpp

#include "Windows.h"
#include "Bottom_Panel.h"

void Test2()
{
    // Initializing new console screen_buffer
    HANDLE Screen_Buffer_Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CONSOLE_TEXTMODE_BUFFER, 0);
    CONSOLE_SCREEN_BUFFER_INFO Screen_Buffer_Info{};
    SetConsoleActiveScreenBuffer(Screen_Buffer_Handle);
    GetConsoleScreenBufferInfo(Screen_Buffer_Handle, &Screen_Buffer_Info);
    int screen_buffer_size = (int)Screen_Buffer_Info.dwSize.X * (int)Screen_Buffer_Info.dwSize.Y;
    CHAR_INFO* Screen_Buffer = new CHAR_INFO[screen_buffer_size];

    // Bug causing part:
    AsBottom_Panel* Bottom_Panel = new AsBottom_Panel(Screen_Buffer, Screen_Buffer_Info.dwSize.X, 0, Screen_Buffer_Info.dwSize.Y - 1);
    while (true)
    {
        Bottom_Panel->Draw();
        Sleep(10);
    }
}

int main()
{
    Test2();
    return 0;
}

文件Bottom_Panel.cpp:

#include "Bottom_Panel.h"

// ABottom_Panel_Item

ABottom_Panel_Item::ABottom_Panel_Item(std::wstring key, std::wstring name)
    : Key(key), Name(name), Key_Size(key.size())
{
}

void ABottom_Panel_Item::Draw(CHAR_INFO* screen_buffer, unsigned short x_pos, unsigned short y_pos, 
                              unsigned short screen_width, unsigned short limit)
{
    for (int i = 0; i < Key_Size; ++i)
    {
        CHAR_INFO ch;
        ch.Attributes = 0x07;
        ch.Char.UnicodeChar = Key[i];
        screen_buffer[y_pos * screen_width + x_pos + i] = ch;
    }

    for (int i = 0; i < limit; ++i)
    {
        CHAR_INFO ch;
        ch.Attributes = 0xb0;
        if (i < Name.size())
        {
            ch.Char.UnicodeChar = Name[i];
        }
        else
        {
            ch.Char.UnicodeChar = ' ';
        }
        screen_buffer[y_pos * screen_width + x_pos + i + Key_Size] = ch;
    }
}


// AsBottom_Panel

AsBottom_Panel::AsBottom_Panel(CHAR_INFO* screen_buffer, unsigned short screen_width, 
                               unsigned short x_pos, unsigned short y_pos)
    : Screen_Buffer(screen_buffer), Screen_Width(screen_width), X_Pos(x_pos), Y_Pos(y_pos)
{
    Items[0] = new ABottom_Panel_Item(L"1", L"Help");
    Items[1] = new ABottom_Panel_Item(L"2", L"UserMenu");
    Items[2] = new ABottom_Panel_Item(L"3", L"View");
    Items[3] = new ABottom_Panel_Item(L"4", L"Edit");
    Items[4] = new ABottom_Panel_Item(L"5", L"Copy");
    Items[5] = new ABottom_Panel_Item(L"6", L"RenMov");
    Items[6] = new ABottom_Panel_Item(L"7", L"MakeDir");
    Items[7] = new ABottom_Panel_Item(L"8", L"Delete");
    Items[8] = new ABottom_Panel_Item(L"9", L"Config");
    Items[9] = new ABottom_Panel_Item(L"10", L"Quit");
}

void AsBottom_Panel::Draw()
{
    int step = Screen_Width / 10; // Screen_Width = 120 on my PC
    for (int i = 0; i < 10; i++)
    {
        Items[i]->Draw(Screen_Buffer, X_Pos, Y_Pos, Screen_Width, 8);
        X_Pos += step;
    }
}

文件Bottom_Panel.h:

#pragma once

class ABottom_Panel_Item
{
public:
    ABottom_Panel_Item(std::wstring key, std::wstring name);

    void Draw(CHAR_INFO* screen_buffer, unsigned short x_pos, unsigned short y_pos, 
              unsigned short screen_width, unsigned short limit);

private:
    const std::wstring Key;
    const std::wstring Name;
    int Key_Size;
};

class AsBottom_Panel
{
public:
    AsBottom_Panel(CHAR_INFO* screen_buffer, unsigned short screen_width, unsigned short x_pos, 
                   unsigned short y_pos);

    void Draw();

private:
    unsigned short X_Pos, Y_Pos;
    unsigned short Screen_Width;
    CHAR_INFO* Screen_Buffer;
    ABottom_Panel_Item* Items[10]{};
};

我遇到异常:

Exception thrown: read access violation.
std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >::operator[](...) returned 0xFFFFFFFFFFFFFFFF.
我在

Bottom_Panel 的构造函数中初始化的我的 Bottom_Panel_Item 对象已损坏。当我设置断点来查看发生的情况时,我看到的是

<error reading characters of string>
而不是我的变量。 我尝试使用预定义的字符数组
wchar_t Key[10]
wchar_t Name[10]
- 没有结果。 当我在 while 循环中第二次调用
Draw()
方法时,就会出现问题。我猜想在某些时候内存会被覆盖在某个地方。

c++ windows
1个回答
0
投票

我将主要解决至少一个代码问题及其发生位置。

但是,为了解决这个问题,我获取了您的代码并将其更改为使用

std::vector<CHAR_INFO>
而不是
CHAR_INFO*
。这使我能够轻松诊断越界访问。

执行此操作时,再加上在 Visual Studio 中以调试模式运行程序,我得到一个下标超出范围断言,恰好在

screen_buffer
访问范围内。

这是您的代码的重写:

#include <windows.h>
#include <string>
#include <vector>

using SBuffer = std::vector<CHAR_INFO>;
class ABottom_Panel_Item
{
public:
    ABottom_Panel_Item(std::wstring key, std::wstring name);

    void Draw(SBuffer& screen_buffer, unsigned short x_pos, unsigned short y_pos,
        unsigned short screen_width, unsigned short limit);

private:
    const std::wstring Key;
    const std::wstring Name;
    int Key_Size;
};

class AsBottom_Panel
{
public:
    AsBottom_Panel(SBuffer& screen_buffer, unsigned short screen_width, unsigned short x_pos,
        unsigned short y_pos);

    void Draw();

private:
    unsigned short X_Pos, Y_Pos;
    unsigned short Screen_Width;
    SBuffer Screen_Buffer;
    ABottom_Panel_Item* Items[10]{};
};

ABottom_Panel_Item::ABottom_Panel_Item(std::wstring key, std::wstring name)
    : Key(key), Name(name), Key_Size(key.size())
{
}

void ABottom_Panel_Item::Draw(SBuffer& screen_buffer, unsigned short x_pos, unsigned short y_pos,
    unsigned short screen_width, unsigned short limit)
{
    for (int i = 0; i < Key_Size; ++i)
    {
        CHAR_INFO ch;
        ch.Attributes = 0x07;
        ch.Char.UnicodeChar = Key[i];
        screen_buffer[y_pos * screen_width + x_pos + i] = ch; // <-- Error here
    }

    for (int i = 0; i < limit; ++i)
    {
        CHAR_INFO ch;
        ch.Attributes = 0xb0;
        if (i < Name.size())
        {
            ch.Char.UnicodeChar = Name[i];
        }
        else
        {
            ch.Char.UnicodeChar = ' ';
        }
        screen_buffer[y_pos * screen_width + x_pos + i + Key_Size] = ch;
    }
}


// AsBottom_Panel

AsBottom_Panel::AsBottom_Panel(SBuffer& screen_buffer, unsigned short screen_width,
    unsigned short x_pos, unsigned short y_pos)
    : Screen_Buffer(screen_buffer), Screen_Width(screen_width), X_Pos(x_pos), Y_Pos(y_pos)
{
    Items[0] = new ABottom_Panel_Item(L"1", L"Help");
    Items[1] = new ABottom_Panel_Item(L"2", L"UserMenu");
    Items[2] = new ABottom_Panel_Item(L"3", L"View");
    Items[3] = new ABottom_Panel_Item(L"4", L"Edit");
    Items[4] = new ABottom_Panel_Item(L"5", L"Copy");
    Items[5] = new ABottom_Panel_Item(L"6", L"RenMov");
    Items[6] = new ABottom_Panel_Item(L"7", L"MakeDir");
    Items[7] = new ABottom_Panel_Item(L"8", L"Delete");
    Items[8] = new ABottom_Panel_Item(L"9", L"Config");
    Items[9] = new ABottom_Panel_Item(L"10", L"Quit");
}

void AsBottom_Panel::Draw()
{
    int step = Screen_Width / 10; // Screen_Width = 120 on my PC
    for (int i = 0; i < 10; i++)
    {
        Items[i]->Draw(Screen_Buffer, X_Pos, Y_Pos, Screen_Width, 8);
        X_Pos += step;
    }
}

void Test2()
{
    // Initializing new console screen_buffer
    HANDLE Screen_Buffer_Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CONSOLE_TEXTMODE_BUFFER, 0);
    CONSOLE_SCREEN_BUFFER_INFO Screen_Buffer_Info{};
    SetConsoleActiveScreenBuffer(Screen_Buffer_Handle);
    GetConsoleScreenBufferInfo(Screen_Buffer_Handle, &Screen_Buffer_Info);
    int screen_buffer_size = (int)Screen_Buffer_Info.dwSize.X * (int)Screen_Buffer_Info.dwSize.Y;
    SBuffer Screen_Buffer(screen_buffer_size);

    // Bug causing part:
    AsBottom_Panel* Bottom_Panel = new AsBottom_Panel(Screen_Buffer, Screen_Buffer_Info.dwSize.X, 0, Screen_Buffer_Info.dwSize.Y - 1);
    while (true)
    {
        Bottom_Panel->Draw();
        Sleep(10);
    }
}

int main()
{
    Test2();
    return 0;
}

发生错误是因为

screen_buffer
的大小为 3600,但在某些时候您正在访问
screen_buffer[y_pos * screen_width + x_pos + i]
,其中
y_pos * screen_width + x_pos + i
等于 3600。这是越界访问,因为
screen_buffer[3600]
超出了范围界限。

© www.soinside.com 2019 - 2024. All rights reserved.