libsdl-org / SDL_image

Image decoding for many popular formats for Simple Directmedia Layer.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IMG_Load segfault after SDL_FreeSurface

FullPtrDereference opened this issue · comments

SDL ver. 2.26.5, SDL_image ver. 2.6.3. Both built by me using CMake.
Only crashes with LLDB attached, but this is preventing me getting to a different bug in my own code.

(lldb) ru
Process 12792 launched: '<snip>\a.exe' (x86_64)
Process 12792 stopped
* thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff8f02a8e55: Access violation reading location 0xffffffffffffffff
    frame #0: 0x00007ff8f02a8e55 SDL2.dll`SDL_DYNAPI_entry + 1202181
SDL2.dll`SDL_DYNAPI_entry:
->  0x7ff8f02a8e55 <+1202181>: cmp    eax, dword ptr [rcx]
    0x7ff8f02a8e57 <+1202183>: jne    0x7ff8f02a8e86            ; <+1202230>
    0x7ff8f02a8e5d <+1202189>: mov    rax, qword ptr [rsp + 0x20]
    0x7ff8f02a8e62 <+1202194>: mov    ecx, dword ptr [rax + 0x2c]
(lldb) bt
* thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff8f02a8e55: Access violation reading location 0xffffffffffffffff
  * frame #0: 0x00007ff8f02a8e55 SDL2.dll`SDL_DYNAPI_entry + 1202181
    frame #1: 0x00007ff8f02b0633 SDL2.dll`SDL_DYNAPI_entry + 1232867
    frame #2: 0x00007ff8f02b102a SDL2.dll`SDL_DYNAPI_entry + 1235418
    frame #3: 0x00007ff8f01809ff SDL2.dll`SDL_CreateRGBSurfaceWithFormatFrom + 79
    frame #4: 0x00007ff8f4b1d0d9 SDL2_imaged.dll`IMG_LoadSTB_RW(src=0x0000024f5f837440) at IMG_stb.c:117:19
    frame #5: 0x00007ff8f4b15063 SDL2_imaged.dll`IMG_LoadPNG_RW(src=0x0000024f5f837440) at IMG_png.c:509:12
    frame #6: 0x00007ff8f4b11838 SDL2_imaged.dll`IMG_LoadTyped_RW(src=0x0000024f5f837440, freesrc=1, type="png") at IMG.c:289:17
    frame #7: 0x00007ff8f4b116db SDL2_imaged.dll`IMG_Load(file="Q:\\IMG\\759483405020430377_1048984769142214736.png") at IMG.c:205:12
    frame #8: 0x00007ff6f5ec2892 a.exe`main((null)=1, (null)=0x0000024f549a8aa0) at main.cc:35:5
    frame #9: 0x00007ff6f5ec13d7 a.exe`__tmainCRTStartup at crtexe.c:321:15
    frame #10: 0x00007ff6f5ec1436 a.exe`mainCRTStartup at crtexe.c:202:9
    frame #11: 0x00007ff96fb67614 kernel32.dll`BaseThreadInitThunk + 20
    frame #12: 0x00007ff96fca26a1 ntdll.dll`RtlUserThreadStart + 33
(lldb) ki
Process 12792 exited with status = 0 (0x00000000)
(lldb) (lldb) q

Attached is minimal code to trigger it and my build "script", look for "<snip>" in the script
main.cc.txt
build.bat.txt

I can't reproduce this with Visual Studio 2019, using SDL 2.26.5 and SDL_image 2.6.3 (self-built from git), and lldb version 9.0.0 (supplied by clion). I don't have clang installed.

Your lldb session shows that it is using SDL2.dll, whereas build.bat says you link to libSDL2.dll.a.
Please verify you don't have a stray SDL2.dll in any folder in your %PATH% environment variable,
and copy freshly built SDL2d.dll/SDL2_imaged.dll to directory where you build your application.
Using the lldb command image list, you can see what modules have been loaded + their path.

I used the source below.
Perhaps you can modify the IMG_Load/SDL_FreeSurface sequence in a way that fails for you?

#define SDL_MAIN_HANDLED
#include "SDL.h"
#include "SDL_image.h"

static const char* pngPath = "image.png";

static SDL_Surface *img_load_and_check(const char *path) {
    SDL_Surface *surface = IMG_Load(path);
    if (surface == NULL) {
        SDL_Log("IMG_Load failed: %s", IMG_GetError());
    }
    return surface;
}

int main(int argc, char* argv[]) {
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_Log("SDL_Init() failed: %s", SDL_GetError());
        return 1;
    }

	if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) {
        SDL_Log("IMG_Init() failed: %s", SDL_GetError());
        return 1;
    }

	SDL_Window *window = SDL_CreateWindow("title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    SDL_Surface *surface = NULL;
    SDL_Surface *surface2 = NULL;
    SDL_Surface *surface3 = NULL;

    SDL_Texture *texture = NULL;

#if 1
    surface = img_load_and_check(pngPath);
    surface2 = img_load_and_check(pngPath);
    surface3 = img_load_and_check(pngPath);
    SDL_FreeSurface(surface);
    surface = surface2; surface2 = NULL;
#else
    surface = img_load_and_check(pngPath);
    SDL_FreeSurface(surface);
    surface = img_load_and_check(pngPath);
    surface2 = img_load_and_check(pngPath);
    surface3 = img_load_and_check(pngPath);
#endif

    texture = SDL_CreateTextureFromSurface(renderer, surface);

    SDL_FreeSurface(surface);
    SDL_FreeSurface(surface2);
    SDL_FreeSurface(surface3);

    if (texture == NULL) {
        SDL_Log("SDL_CreateTextureFromSurface failed: %s", SDL_GetError());
    }

	int exit = 0;

	while (1) {
		for (SDL_Event e; SDL_PollEvent(&e); ) {
			if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) {
				exit = 1;
				break;
			}
		}

		if (exit) {
            break;
        }

		SDL_SetRenderDrawColor(renderer, 0x3b, 0x3b, 0x3b, 0xff);
		SDL_RenderClear(renderer);
        if (texture) {
            SDL_RenderCopy(renderer, texture, NULL, NULL);
        }
		SDL_RenderPresent(renderer);
	}
    
    SDL_DestroyTexture(texture);
    
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

	IMG_Quit();
	SDL_Quit();
}

I've figured it out. I built SDL_image wrong, when I built the debug version I still had SDL2.dll as the library.
I did have SDL 2.0.20 in my path and it would have took me a while to think of that, but fortunately it wasn't down to that.
I did try your code and got the bug at some point, but my memory is hideous and I ended up testing with my code after I rebuilt the libraries.