【问题标题】:Stack smashing detected after closing the sf::RenderWindow关闭 sf::RenderWindow 后检测到堆栈粉碎
【发布时间】:2017-11-17 16:52:32
【问题描述】:

我在编写我的第一个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;
}

【问题讨论】:

  • main函数包含什么?
  • @M4rc 已将主要内容添加到原始帖子中

标签: c++ multithreading sfml


【解决方案1】:

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

这个很大:

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

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

它还会改变对memory 数组的越界访问的影响——而不是弄乱堆栈和改变返回地址之类的东西,任何破坏都会对纯数据对象进行。

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

【讨论】:

  • chip8::kMemSize 为 4KB,这是“规范”CHIP-8 VM 的要求之一。我真的不认为这是很多内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多