SDL_Texture似乎在运行时更改为NULL,从而导致EXC_BAD_ACCESS

时间:2019-01-16 01:50:14

标签: c++ ios sdl-2

我主要用iOS的SDL2用C ++(和一些ObjC)编写游戏。我设法获得了青色背景,但是当我尝试创建图像渲染代码时,它在m_TextureSDL_Texture*)上给了我EXC_BAD_ACCESS。我主要是使用iOS模拟器测试代码。

我试图将空检查添加到m_Texture,并读取SDL_GetError(即使在主循环中)也没有运气。

有问题的崩溃代码在Image::OnUpdate中。我还添加了一条评论来解释在那里进行的检查。 Xcode指出m_TexureNULL

Image.cpp:

#include "Image.hpp"

#include "../Utility/File.hpp"
#include "../Utility/Exception.hpp"
#include "../Rendering/Renderer.hpp"

#define STB_IMAGE_IMPLEMENTATION
#include "../External/stb_image.h"

#include "../External/SDL2/SDL.h"

Image::Image()
    : m_Width(0), m_Height(0), m_X(0), m_Y(0)
{

}

Image::~Image()
{
    SDL_DestroyTexture(m_Texture);
}

void Image::CreateImage(const std::string path, int width, int height, int x, int y)
{
    // TODO: Set req_format into an argument using an enum variable
    int _width, _height, _bpp, req_format = STBI_rgb;

    m_Path = path;
    if(!File::Instance()->FileExists(m_Path))
    {
        throw Exception("File \"" + path + "\" does not exist.");
    }

    unsigned char* _data = stbi_load(m_Path.c_str(), &_width, &_height, &_bpp, req_format);

    int depth, pitch;
    Uint32 pixel_format;
    if (req_format == STBI_rgb)
    {
        depth = 24;

        // 3 bytes per pixel * pixels per row
        pitch = 3*_width;
        pixel_format = SDL_PIXELFORMAT_RGB24;
    }
    else
    {
        // STBI_rgb_alpha (RGBA)
        depth = 32;

        // 4 bytes per pixel * pixels per row
        pitch = 4*_width;
        pixel_format = SDL_PIXELFORMAT_RGBA32;
    }

    SDL_Surface* _surface = SDL_CreateRGBSurfaceWithFormatFrom((void*)_data, _width, _height, depth, pitch, pixel_format);
    if(_surface == NULL)
    {
        throw Exception("Cannot create surface from image " + m_Path + ":" + std::string(SDL_GetError()));
    }
    stbi_image_free(_data);

    m_Texture = SDL_CreateTextureFromSurface(Renderer::Instance()->GetRenderer(), _surface);
    if(m_Texture == NULL)
    {
        throw Exception("Cannot create texture from image " + m_Path + ":" + std::string(SDL_GetError()));
    }
    SDL_FreeSurface(_surface);

    m_X = x;
    m_Y = y;
    m_Width = width;
    m_Height = height;

    m_Rect.x = x;
    m_Rect.y = y;
    m_Rect.w = width;
    m_Rect.h = height;

    // Make sure that the texture is enabled by default.
    m_IsEnabled = true;
}

bool Image::IsEnabled()
{
    return m_IsEnabled;
}

void Image::OnUpdate()
{
    // This !m_Texture check was added as part of my debugging process. It crashes here regardless if this check is here or not.
    if(!m_Texture)
    {
        throw Exception("Texture was null during Image::OnUpdate: " + std::string(SDL_GetError()));
    }
    SDL_RenderCopy(Renderer::Instance()->GetRenderer(), m_Texture, NULL, NULL);
}

void Image::Show()
{
    m_IsEnabled = true;
}

void Image::Hide()
{
    m_IsEnabled = false;
}

Image.hpp:

#ifndef Image_hpp
#define Image_hpp

#include <string>

//#include "../Rendering/Renderer.hpp"

#include "../External/SDL2/SDL.h"

class Image
{
    std::string m_Path;
    int m_Width, m_Height;
    int m_X, m_Y;
    bool m_IsEnabled;

    SDL_Texture* m_Texture;
    SDL_Rect m_Rect;
public:
    Image();
    ~Image();

    void CreateImage(const std::string path, int width, int height, int x, int y);
    void OnUpdate();
    void Show();
    void Hide();
    bool IsEnabled();
};

#endif /* Image_hpp */

这是Xcode Logging输出(注意可能无用的调试消息):

2019-01-16 01:48:35.901338+0000 Grass Cut[7972:822083] Unknown class GameViewController in Interface Builder file.
2019-01-16 01:48:35.919865+0000 Grass Cut[7972:822083] DEBUG: Screen Size Native: 320x568
2019-01-16 01:48:35.934069+0000 Grass Cut[7972:822083] [MC] Lazy loading NSBundle MobileCoreServices.framework
2019-01-16 01:48:35.936290+0000 Grass Cut[7972:822083] [MC] Loaded MobileCoreServices.framework
2019-01-16 01:48:35.954627+0000 Grass Cut[7972:822083] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/seanny/Library/Developer/CoreSimulator/Devices/736EB4BE-C093-400E-B35A-CF570DCAF48D/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2019-01-16 01:48:35.988450+0000 Grass Cut[7972:822083] DEBUG: Window created with width of 320 and height of 568.
2019-01-16 01:48:36.030234+0000 Grass Cut[7972:822083] DEBUG: Game Engine initialized, starting main loop.
2019-01-16 01:48:36.030451+0000 Grass Cut[7972:822083] WARNING: SDL Error: Setting the swap interval is not supported
2019-01-16 01:48:36.030595+0000 Grass Cut[7972:822083] DEBUG: Event OnUpdate
2019-01-16 01:48:36.047651+0000 Grass Cut[7972:822083] WARNING: EVENT: Did Enter Foreground
2019-01-16 01:48:36.048279+0000 Grass Cut[7972:822083] DEBUG: Renderer OnUpdate
(lldb) 

Address Sanitizer输出:

=================================================================
==8833==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000360d8 at pc 0x00010835c5c2 bp 0x7ffee78ae990 sp 0x7ffee78ae988
READ of size 8 at 0x6020000360d8 thread T0
dyld: dyld_sim cannot be loaded in a restricted process
==8833==WARNING: external symbolizer didn't start up correctly!

1 个答案:

答案 0 :(得分:0)

我发现了问题所在,在我的代码中进行了一些挖掘之后,我发现我没有发布的文件的for循环导致了问题。

问题代码:

void Renderer::OnUpdate()
{
    ....
    for(int i = 0; i < (int)sizeof(m_Images); i++)
    {
        if(m_Images[i]->IsEnabled() == true)
        {
            m_Images[i]->OnUpdate();
        }
    }
    ....
}

固定代码:

void Renderer::OnUpdate()
{
    ....
    for(int i = 0; i < m_Images.size(); i++)
    {
        if(m_Images[i]->IsEnabled() == true)
        {
            m_Images[i]->OnUpdate();
        }
    }
    ....
}