关闭 sf::RenderWindow 后检测到堆栈粉碎

Stack smashing detected after closing the sf::RenderWindow

本文关键字:堆栈 sf RenderWindow 关闭 检测      更新时间:2023-10-16

我正在编写我的第一个 chip8 解释器和多线程程序,并遇到了这个问题:一旦我关闭窗口,我就会检测到堆栈粉碎。我已经检查代码很长时间了,但我找不到问题。真的很想得到一些帮助或建议。

模拟器.hpp

#ifndef CHEAP8_SRC_EMULATOR_HPP
#define CHEAP8_SRC_EMULATOR_HPP
#include "chip8.hpp"
#include "ui-settings.hpp"
#include <SFML/Graphics.hpp>
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#ifdef _WIN32
#define OS_PATH_SEP ''
#else
#define OS_PATH_SEP '/'
#endif
class Emulator
{
    //misc
    const std::string gamePath;
    const std::string gameTitle;
    //emulator
    unsigned char memory[chip8::kMemSize] = {0};
    //flags
    bool gameLoaded = false;
    std::atomic<bool> gameRunning{false};
    //ui
    const double kPixelSize = 12.5;
    std::shared_ptr<sf::RenderWindow> window;
    const UiSettings uiSettings;
    //threading
    std::thread uiThread;
    std::mutex mutex;
    void loadGame();
    void loadFonts();
public:
    explicit Emulator(char*);
    ~Emulator();
    void run();
};
#endif //CHEAP8_SRC_EMULATOR_HPP

模拟器.cpp

#include "emulator.hpp"
#include <chrono> //================
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
void launchUi(std::shared_ptr<sf::RenderWindow> window,
              const UiSettings& uiSettings,
              std::atomic<bool>& gameRunning)
{
    window = std::make_shared<sf::RenderWindow>();
    window->create(sf::VideoMode(uiSettings.width, uiSettings.height),
                   uiSettings.title,
                   sf::Style::Titlebar | sf::Style::Close);
    window->setVerticalSyncEnabled(true);
    window->setKeyRepeatEnabled(false);
    const auto screenParams = sf::VideoMode::getDesktopMode();
    window->setPosition(sf::Vector2i(screenParams.width / 2 - uiSettings.width / 2,
                                     screenParams.height / 2 - uiSettings.height / 2));
    sf::Event event;
    while (window->isOpen()) {
        while (window->pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window->close();
                    gameRunning.store(false);
                break;
                default:
                break;
            }
        }
    }
}
Emulator::Emulator(char* path)
    : gamePath(path),
      gameTitle(gamePath.substr(gamePath.find_last_of(OS_PATH_SEP) + 1)),
      uiSettings(kPixelSize, chip8::kScreenWidth, chip8::kScreenHeight, gameTitle),
      uiThread(launchUi, window, std::ref(uiSettings), std::ref(gameRunning))
{
    loadGame();
    loadFonts();
}
Emulator::~Emulator()
{
    uiThread.join();
}
void Emulator::loadGame()
{
    std::ifstream file(gamePath, std::ios::binary);
    if (!file.is_open()) {
        std::cerr << "Couldn't open the game." << std::endl;
        return;
    }
    std::vector<unsigned char> gameData;
    gameData.insert(gameData.begin(),
                std::istream_iterator<unsigned char>(file),
                std::istream_iterator<unsigned char>());
    if (gameData.size() > chip8::kAllowedGameSize) {
        std::cerr << "The game is too big to fit into memory." << std::endl;
        return;
    }
    for (size_t i = 0; i < gameData.size(); ++i) {
        memory[i + chip8::kMemStart] = gameData[i];
    }
    gameLoaded = true;
    std::cout << "Game loaded. Size: " << gameData.size() << 'n';
}
void Emulator::loadFonts()
{
    for (int i = 0; i < chip8::kFontsetSize; ++i) {
        memory[i] = chip8::kFontset[i];
    }
    std::cout << "Fontset loaded." << 'n';
}
void Emulator::run()
{
    if (!gameLoaded) {
        return;
    }
    gameRunning.store(true);
    while (gameRunning.load()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

编辑:

#include "emulator.hpp"
#include <iostream>
int main(int argc, char *argv[])
{
    if (argc != 2) {
        std::cerr << "Usage: ./" << OS_PATH_SEP << "cheap8 game." << std::endl;
        return 1;
    }
    Emulator emu(argv[1]);
    emu.run();
    return 0;
}

您的 Emulator 实例是在堆栈上创建的,因此它将使用足以存储其所有成员变量的堆栈空间。

这个很大:

unsigned char memory[chip8::kMemSize] = {0};

您可以将其更改为 std::vector,以便它将数据存储在堆上,并且类实例仅包含元数据(大小、指向数据的指针(。

它还将改变对memory数组的越界访问的效果 - 而不是弄乱堆栈和更改返回地址等内容,任何损坏都将对纯数据对象进行。

为了确保没有越界访问,您可以使用 vector 的 at() 成员函数。