Segfault при сохранении PNG с SDL_image - PullRequest
0 голосов
/ 05 октября 2019

Мне нужно создать OCR в C, используя SDL2 и SLD2_image.

Все отлично работает на macOS. Однако при запуске моей программы в Linux при сохранении файла PNG возникает ошибка.

Я пытался обновить используемые библиотеки (SDL2, SDL2_image и libpng) и смог сохранить только черное изображение и получитьошибка на IMG_QUIT () или SDL_QUIT ()

Так что мой код падает на IMG_SavePNG(surface, "textmono.png")

Я также пытался

SDL_SaveBMP(surface, "textmono.bmp")

И получил тот же результат ...

Вот мой код:

void BlackAndWhite(SDL_Surface* surface){
    Uint32 *pixels = (Uint32 *)surface->pixels;
    for(int i = 0; i < surface->h; i++){
        for(int j = 0; j < surface->w;j++){
            Uint8 red = 0;
            Uint8 green = 0;
            Uint8 blue = 0;
            SDL_GetRGB(pixels[i*surface->w + j], surface->format, &red, &green, &blue);
            Uint8 black = (red + green + blue)/3;
            pixels[i*surface->w + j] = SDL_MapRGB(surface->format, black, black, black);
        }
    }
    IMG_SavePNG(surface, "textbw.png");
}

А вот как я загружаю свой png-файл:

int loadimage(void){
    if(SDL_Init(SDL_INIT_VIDEO)==-1)
    {
        printf("SDL_Init: %s\n", SDL_GetError());
        return 1;
    }
    IMG_Init(~0);
    SDL_Surface *surface =  IMG_Load("text.png");
    if(surface != NULL){
        ...
    }
    else{
        printf("Failed ! %s\n", IMG_GetError());
    }
    return 0;
}

GDB дает мне следующее:

Thread 1 "main" received signal SIGSEGV, Segmentation fault.
0x00007ffff7cc947d in _int_malloc (av=av@entry=0x7ffff7e16c40 <main_arena>, 
    bytes=bytes@entry=1304) at malloc.c:3880
3880    malloc.c: Aucun fichier ou dossier de ce type.
(gdb) where
    0x00007ffff7cc947d in _int_malloc (
    av=av@entry=0x7ffff7e16c40 <main_arena>, bytes=bytes@entry=1304)
    at malloc.c:3880
   0x00007ffff7ccacaa in __GI___libc_malloc (bytes=1304) at malloc.c:3073
   0x00007ffff3894e74 in png_malloc_warn ()
   from /lib/x86_64-linux-gnu/libpng16.so.16
   0x00007ffff388ec41 in ?? () from /lib/x86_64-linux-gnu/libpng16.so.16
   0x00007ffff38ab88e in png_create_write_struct_2 ()
   from /lib/x86_64-linux-gnu/libpng16.so.16
   0x00007ffff38ab931 in png_create_write_struct ()
   from /lib/x86_64-linux-gnu/libpng16.so.16
   0x00007ffff7e47d88 in IMG_SavePNG_RW_libpng (surface=0x5555558c9f00, 
    dst=0x5555557fca40, freedst=1) at IMG_png.c:544
    0x000055555555531f in BlackAndWhite (surface=0x5555558c9f00) at main.c:60
   0x00005555555554d0 in loadimage () at main.c:38
   0x0000555555555116 in main () at main.c:21

EDIT : AddressSanitizer сообщает мне, что переполнение буфера динамической памяти в

SDL_GetRGB(pixels[i*surface->w + j], surface->format, &red, &green, &blue)

Удаление этой части кода действительно решает проблему, поэтому я полагаю, что янашел проблему, но я не понимаю, что не так с этой строкой ...

Ответы [ 2 ]

0 голосов
/ 06 октября 2019

Хорошо, поэтому я использовал другой способ получения и установки пикселей, и теперь все работает ... Мой код теперь выглядит следующим образом:

void BlackAndWhite(SDL_Surface* surface){
    int i = 0;
    int j = 0;
    for(i = 0; i < surface->h; i++){
        for(j = 0; j < surface->w;j++){
            Uint8 red = 0;
            Uint8 green = 0;
            Uint8 blue = 0;
            Uint32 pixel = getpixel(surface,j,i);
            SDL_GetRGB(pixel, surface->format, &red, &green, &blue);
            Uint8 black = (red + green + blue)/3;
            pixel = SDL_MapRGB(surface->format, black, black, black);
            putpixel(surface,j,i,pixel);
        }
    }
    IMG_SavePNG(surface, "textbw.png");
}
putpixel 

и

getpixel 

соответствующих функций на этой странице: Пиксельный доступ - SDL

0 голосов
/ 06 октября 2019

GDB дает мне следующее:

Любой сбой внутри malloc или free обычно (99,9% времени) означает, что у вас повреждение кучи (например, переполнение памяти, выделенной в куче, free что-то дважды, free нераспределенная память и т. д. и т. д.).

Такие ошибки довольно сложно найти, особенно при использовании 3-госторонние библиотеки и плохо понимают их требования.

К счастью, есть инструменты, которые облегчают поиск и понимание таких ошибок много : Valgrind и addresssanitizer .

Используйте один из них, и ошибка, вероятно, будет очевидна. Если это не так, вы можете отредактировать свой вопрос с помощью инструмента, который вы использовали, и вы, вероятно, получите лучший ответ.

...