SDL_GetRendererInfo crash

2019-09-18 20:01发布

问题:

the following program runs until SDL_GetRendererInfo is called (in function RenderInit()), and then stops working before SDL_GetError can do anything. replacing global_renderer with a null SDL_Renderer pointer doesn't cause a crash and the expected sdl error is gotten.

#include <iostream>
#include <list>
#include "SDL.h"
using namespace std;
//global variables:
bool run = true; // whether or not the program should be running

int global_window_width = 50; //width of window in tiles

int global_window_height = 35; //height of window in tiles

SDL_Window* global_window = NULL; //points to primary window

SDL_Renderer* global_renderer = NULL; //points to renderer for main window

SDL_RendererInfo* global_renderer_info = NULL; //points to info about above renderer once it's initialized

SDL_Texture* spritesheet = NULL; //holds the spritesheet

SDL_Event event; //for holding currently in-handling event

//function declarations:
int init();  //initialize SDL

int windowInit(); //initialize window

int renderInit(); //create renderers

int viewInit(); //manages all window, rendering, etc stuff

int loadSpritesheet(); //loads spritesheet

void cleanup(); //free up memory, etc

void dispatchEvent(); //main event handling

//function definitions:
int init()
{
    if ( SDL_Init(SDL_INIT_EVERYTHING) !=0 )
    {
        cout << "could not initialize SDL. " << SDL_GetError();
        return 1;
    }

    return 0;
}

int windowInit()
{
    global_window = SDL_CreateWindow("roguelike",
                                  SDL_WINDOWPOS_UNDEFINED,
                                  SDL_WINDOWPOS_UNDEFINED,
                                  global_window_width * 10,
                                  global_window_height * 10,
                                  SDL_WINDOW_SHOWN);
    if(global_window == NULL)
    {
        cout << "could create window. " << SDL_GetError();
        return 1;
    }
    return 0;
}

int renderInit()
{
        global_renderer = SDL_CreateRenderer(global_window,
                                             -1,
                                             SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED );
        if (global_renderer == NULL)
        {
            cout << "could not create renderer" << SDL_GetError();
            return 1;
        }
        SDL_SetRenderDrawColor(global_renderer,0xFF,0xFF,0xFF,0xFF);
        if (SDL_GetRendererInfo(global_renderer, global_renderer_info) != 0)
        {
            cout << "could not get renderer info" << SDL_GetError();
            return 1;
        }

        return 0;
}

int viewInit()
{
    if (windowInit() == 1)
    {
        return 1;
    }
    else if(renderInit() == 1)
    {
        return 1;
    }
    else if(loadSpritesheet() == 1)
    {
        return 1;
    }
    return 0;
}

int loadSpritesheet()
{
    SDL_Surface* tempsurf = NULL; //using surface to get image initially, but since surfaces use cpu rendering we switch to textures immediately

    tempsurf = SDL_LoadBMP("spritesheet.bmp"); //puts image in the surface

    if (tempsurf == NULL)
    {
        cout << "failed to load spritesheet";
        SDL_FreeSurface(tempsurf); //we don't need tempsurf anymore
        return 1;
    }
    spritesheet = SDL_CreateTextureFromSurface(global_renderer, tempsurf);
    if (spritesheet == NULL)
    {
        cout << "failed to create spritesheet texture";
        SDL_FreeSurface(tempsurf); //we don't need tempsurf anymore
        return 1;
    }
    SDL_FreeSurface(tempsurf); //we don't need tempsurf anymore
    return 0;
}

void cleanup()
{
    SDL_DestroyWindow(global_window);
    global_window = NULL;
    SDL_DestroyRenderer(global_renderer);
    global_renderer = NULL;
    SDL_DestroyTexture(spritesheet);
    spritesheet = NULL;
    global_renderer_info = NULL;
    SDL_Quit();
}

void dispatchEvent()
{
    SDL_PollEvent(&event); //stores current event information
    switch(event.type)
    {
        case SDL_QUIT:
        {
            run = false;
            break;
        }
    }
}
//classes:

class Layer // each layer holds visuals for a certain subset of what is to be displayed; environment, HUD, menu, etc.
{
    Layer(){};
};

class Camera  //renders environment, ui, etc in a series of layers
{
        int width, height; //in tiles
        SDL_Texture* texture_draw; //texture the camera draws to and sends to be displayed
        list<Layer*> layer_list; //list of layers to be rendered, back --> front
    public:
        Camera(int x, int y, SDL_Renderer* renderer): width(x), height(y) //(width, height, renderer for camera to use)
        {
            texture_draw = SDL_CreateTexture(global_renderer,global_renderer_info->texture_formats[0] , SDL_TEXTUREACCESS_TARGET, 10*width, 10*height);
        };
};

//main loop
int main(int argc, char *argv[]) //main function, needed by SDL
{
    if(init() == 0)
    {
        if(viewInit() == 0)
        {
            while(run)
            {
                dispatchEvent();

            }
        }
    }
    cleanup();
    return 0;
}

回答1:

You're asking SDL_GetRendererInfo to write renderer info to location global_renderer_info points to, which is NULL. Writing to NULL causes segmentation fault. This should be expected behaviour.

Correct code should allocate memory for renderer info (preferably on stack or in global area) and write to that location, e.g.:

SDL_RendererInfo info = {0};
SDL_GetRendererInfo(global_renderer, &info);
// ... use info fields


回答2:

Fixed by: instead of declaring global_renderer_info as a pointer to an SDL_RendererInfo, I instead declared the object directly and changed the rest of the code accordingly.



标签: c++ sdl-2