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

SDL_Texture seems to changing to NULL during runtime, causing EXC_BAD_ACCESS

本文关键字:NULL 导致 BAD ACCESS EXC Texture SDL 运行时      更新时间:2023-10-16

我主要用C++(和一些ObjC)编写一款游戏,SDL2适用于iOS。我已经设法获得了青色背景,但当我尝试创建图像渲染代码时,它会在m_Texture(SDL_Texture*)上为我提供EXC_BAD_ACCESS。我主要使用iOS模拟器测试我的代码。

我曾尝试向m_Texture添加空检查,读取SDL_GetError(即使在主循环期间),但都没有成功。

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

图片.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;
}

图片.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日志记录输出(注意可能无用的调试消息):

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) 

地址消毒器输出:

=================================================================
==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!

我发现了问题所在,在我的代码中进行了一些挖掘后,我注意到一个我没有发布的文件的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();
}
}
....
}