c - 调用 FreeImage_GetPixelColor() 时出现奇怪的段错误

标签 c image segmentation-fault rgb freeimage

我一直在使用 FreeImage 库编写一些图像压缩 C 代码。在大部分调试图像压缩代码之后,我的程序现在在 FreeImage 库中出现段错误:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff77bc92c in FreeImage_GetPixelColor (dib=0x5555557847b0, x=0, 
    y=<optimized out>, value=0x555555554e70 <_start>)
    at Source/FreeImage/PixelAccess.cpp:97
97  Source/FreeImage/PixelAccess.cpp: No such file or directory.

我不知道为什么会收到此错误。根据 GDB,问题可能是我以错误的方式访问 RGBQUAD 指针,但我不确定。

此外,由 GIMP 创建并提供给 FreeImage 的任何 TIFF 文件都会在 STDERR 上生成大量非 fatal error 消息。我提供的用于测试我的代码的 TIFF 文件是使用 GIMP 生成的 512x512px 实心蓝色方 block 。另外,奇怪的是,当我在我的代码中将 calloc() 更改为 malloc() 时,FreeImage 库似乎没有出现问题(我使用 calloc() 来初始化我的数据结构。它们是整型和浮点型都需要清零)。

我在 Linux Mint 19.1 Cinnamon x86 64 位和 FreeImage 库版本 3 上运行。

段错误是在图像压缩代码开始时从 main() 调用的 getPixels() 函数中生成的:

#include "ccc-common.h"

//Global variable which indicates if a FreeImage library function has encountered an error
int errorlevel = 0;

void check_indices(int index1, int bound1) {
    if (index1 >= bound1) {
        errorlevel = 1;
    }
}

//Function to free() malloc() allocated 2D arrays
void error_free(void *p1, void *p2, void* p3) {
    free(p1);
    free(p2);
    free(p3);
}

//Note : This function was copied from the FreeImage developer documentation
/** Generic image loader
@param lpszPathName Pointer to the full file name
@param flag Optional load flag constant
@return Returns the loaded dib if successful, returns NULL otherwise
*/
FIBITMAP* GenericLoader(const char* lpszPathName, int flag) {
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
    // check the file signature and deduce its format
    // (the second argument is currently not used by FreeImage)
    fif = FreeImage_GetFileType(lpszPathName, 0);
    if(fif == FIF_UNKNOWN) {
        // no signature ?
        // try to guess the file format from the file extension
        fif = FreeImage_GetFIFFromFilename(lpszPathName);
    }
    // check that the plugin has reading capabilities ...
    if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
        // ok, let's load the file
        FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, flag);
        // unless a bad file format, we are done !
        return dib;
    }
    return NULL;
}

//Note : This function is based on a similar function in the FreeImage developer documentation
/**
FreeImage error handler
@param fif Format / Plugin responsible for the error
@param message Error message
*/
//Error handler for FreeImage library functions
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message) {
    //printf("Error : *** \n");
    printf(" *** \n");
    if(fif != FIF_UNKNOWN) {
        //printf("Format is type %s\n It *MUST* be type BMP, JPEG, PNG or TIFF\n", FreeImage_GetFormatFromFIF(fif));
        printf("Format is type %s\n It *MUST* be type BMP, JPEG, PNG or TIFF\n", FreeImage_GetFormatFromFIF(fif));
    }
    printf("%s\n", message);
    printf(" *** \n");
    errorlevel = 1; //Set errorlevel global variable to 1 to indicate that an error condition was detected
}

//Generic 2-dimensional array access functions

//Sets an element in a 2D array with bounds check
#ifdef DEBUG1
*void setElement(void *array1, int width1, size_t elementSize, int x, int y, const void *element, int max_size) {
    if ((x*elementSize + y*width1*elementSize) > max_size) {
        fprintf(stderr, "ERROR : setElement() tried to access an out-of-bounds element...\n");
        fprintf(stderr, "Arguments were -- width1 : %i , elementSize : %i , x : %i , y : %i , max_size : %i \n", width1, (int) elementSize, x, y, max_size);
        errorlevel = 1;
        return;
    }
    memcpy((array1 + y*width1*(elementSize) + (x*elementSize)), element, elementSize);
}
#else
void setElement(void *array1, int width1, size_t elementSize, int x, int y, const void *element) {
    memcpy((array1 + y*width1*(elementSize) + (x*elementSize)), element, elementSize);
}
#endif

#ifdef DEBUG1
//Gets an element in a 2D array with bounds check
void *getElement(void *array1, int width1, size_t elementSize, int x, int y, int max_size) {
    if ((x*elementSize + y*width1*elementSize) > max_size) {
        fprintf(stderr, "ERROR : getElement() tried to access an out-of-bounds element...\n");
        fprintf(stderr, "Arguments were -- width1 : %i , elementSize : %i , x : %i , y : %i , max_size : %i \n", width1, (int) elementSize, x, y, max_size);
        errorlevel = 1;
        return;
    }
    return (array1 + y*width1*(elementSize) + ((x*elementSize)));
}
#else
void *getElement(void *array1, int width1, size_t elementSize, int x, int y) {
    return (array1 + y*width1*(elementSize) + ((x*elementSize)));
}
#endif


//Function needed by qsort when the color histogram needs to be sorted
int compare_colors(const void *a, const void *b) {
    return ( *(int*)a - *(int*)b );
}

//Initializes the pixels 2-dimensional array
void getPixels(FIBITMAP *image, pixel *pixels1, int width1, int height1) {
    for (int y = 0; y < height1; y++) {
        for (int x = 0; x < width1; x++) {
            RGBQUAD *rgb1;
#ifdef DEBUG1
            int pixels_max_size1 = width1*height1*sizeof(pixel);
#endif

            if(!FreeImage_GetPixelColor(image, (unsigned) x, (unsigned) y, rgb1)) {
                fprintf(stderr, "FreeImage_GetPixelColor error\n");
                errorlevel = 1;
                return;
            }
#ifdef DEBUG1
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y, pixels_max_size1);
#else
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y);
#endif
#ifdef DEBUG1
            if (errorlevel) {
                return;
            }
#endif
            t1->color = (uint32_t) (((uint8_t) rgb1->rgbRed) << 16) + (((uint8_t) rgb1->rgbGreen) << 8) + ((uint8_t) (rgb1->rgbBlue));
            t1->r = (uint8_t) (rgb1->rgbRed);
            t1->g = (uint8_t) (rgb1->rgbGreen);
            t1->b = (uint8_t) (rgb1->rgbBlue);
        }
    }
}

变量 t1 是指向 pixel 结构的二维数组的指针:

struct pixel {
    uint32_t color;
    uint8_t r;
    uint8_t g;
    uint8_t b;
};

但是,段错误发生在访问该数组之前

预期的结果是 FreeImage_GetPixelColor 没有段错误。这是 GDB 回溯:

$ gdb ./ccc
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./ccc...done.
(gdb) run test.tiff 
Starting program: /home/jdb2/repos/repos/trunk/ccc/ccc test.tiff
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".


( This program uses FreeImage, a free, open source image library supporting all common bitmap formats. See http://freeimage.sourceforge.net for details ) 

TIFFFieldWithTag: Internal error, unknown tag 0x829a.
TIFFFieldWithTag: Internal error, unknown tag 0x829d.
TIFFFieldWithTag: Internal error, unknown tag 0x8822.
TIFFFieldWithTag: Internal error, unknown tag 0x8824.
TIFFFieldWithTag: Internal error, unknown tag 0x8827.
TIFFFieldWithTag: Internal error, unknown tag 0x8828.
TIFFFieldWithTag: Internal error, unknown tag 0x9000.
TIFFFieldWithTag: Internal error, unknown tag 0x9003.
TIFFFieldWithTag: Internal error, unknown tag 0x9004.
TIFFFieldWithTag: Internal error, unknown tag 0x9101.
TIFFFieldWithTag: Internal error, unknown tag 0x9102.
TIFFFieldWithTag: Internal error, unknown tag 0x9201.
TIFFFieldWithTag: Internal error, unknown tag 0x9202.
TIFFFieldWithTag: Internal error, unknown tag 0x9203.
TIFFFieldWithTag: Internal error, unknown tag 0x9204.
TIFFFieldWithTag: Internal error, unknown tag 0x9205.
TIFFFieldWithTag: Internal error, unknown tag 0x9206.
TIFFFieldWithTag: Internal error, unknown tag 0x9207.
TIFFFieldWithTag: Internal error, unknown tag 0x9208.
TIFFFieldWithTag: Internal error, unknown tag 0x9209.
TIFFFieldWithTag: Internal error, unknown tag 0x920a.
TIFFFieldWithTag: Internal error, unknown tag 0x9214.
TIFFFieldWithTag: Internal error, unknown tag 0x927c.
TIFFFieldWithTag: Internal error, unknown tag 0x9286.
TIFFFieldWithTag: Internal error, unknown tag 0x9290.
TIFFFieldWithTag: Internal error, unknown tag 0x9291.
TIFFFieldWithTag: Internal error, unknown tag 0x9292.
TIFFFieldWithTag: Internal error, unknown tag 0xa000.
TIFFFieldWithTag: Internal error, unknown tag 0xa001.
TIFFFieldWithTag: Internal error, unknown tag 0xa002.
TIFFFieldWithTag: Internal error, unknown tag 0xa003.
TIFFFieldWithTag: Internal error, unknown tag 0xa004.
TIFFFieldWithTag: Internal error, unknown tag 0xa20b.
TIFFFieldWithTag: Internal error, unknown tag 0xa20c.
TIFFFieldWithTag: Internal error, unknown tag 0xa20e.
TIFFFieldWithTag: Internal error, unknown tag 0xa20f.
TIFFFieldWithTag: Internal error, unknown tag 0xa210.
TIFFFieldWithTag: Internal error, unknown tag 0xa214.
TIFFFieldWithTag: Internal error, unknown tag 0xa215.
TIFFFieldWithTag: Internal error, unknown tag 0xa217.
TIFFFieldWithTag: Internal error, unknown tag 0xa300.
TIFFFieldWithTag: Internal error, unknown tag 0xa301.
TIFFFieldWithTag: Internal error, unknown tag 0xa302.
TIFFFieldWithTag: Internal error, unknown tag 0xa401.
TIFFFieldWithTag: Internal error, unknown tag 0xa402.
TIFFFieldWithTag: Internal error, unknown tag 0xa403.
TIFFFieldWithTag: Internal error, unknown tag 0xa404.
TIFFFieldWithTag: Internal error, unknown tag 0xa405.
TIFFFieldWithTag: Internal error, unknown tag 0xa406.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa408.
TIFFFieldWithTag: Internal error, unknown tag 0xa409.
TIFFFieldWithTag: Internal error, unknown tag 0xa40a.
TIFFFieldWithTag: Internal error, unknown tag 0xa40b.
TIFFFieldWithTag: Internal error, unknown tag 0xa40c.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa420.
TIFFFieldWithTag: Internal error, unknown tag 0x829a.
TIFFFieldWithTag: Internal error, unknown tag 0x829d.
TIFFFieldWithTag: Internal error, unknown tag 0x8822.
TIFFFieldWithTag: Internal error, unknown tag 0x8824.
TIFFFieldWithTag: Internal error, unknown tag 0x8827.
TIFFFieldWithTag: Internal error, unknown tag 0x8828.
TIFFFieldWithTag: Internal error, unknown tag 0x9000.
TIFFFieldWithTag: Internal error, unknown tag 0x9003.
TIFFFieldWithTag: Internal error, unknown tag 0x9004.
TIFFFieldWithTag: Internal error, unknown tag 0x9101.
TIFFFieldWithTag: Internal error, unknown tag 0x9102.
TIFFFieldWithTag: Internal error, unknown tag 0x9201.
TIFFFieldWithTag: Internal error, unknown tag 0x9202.
TIFFFieldWithTag: Internal error, unknown tag 0x9203.
TIFFFieldWithTag: Internal error, unknown tag 0x9204.
TIFFFieldWithTag: Internal error, unknown tag 0x9205.
TIFFFieldWithTag: Internal error, unknown tag 0x9206.
TIFFFieldWithTag: Internal error, unknown tag 0x9207.
TIFFFieldWithTag: Internal error, unknown tag 0x9208.
TIFFFieldWithTag: Internal error, unknown tag 0x9209.
TIFFFieldWithTag: Internal error, unknown tag 0x920a.
TIFFFieldWithTag: Internal error, unknown tag 0x9214.
TIFFFieldWithTag: Internal error, unknown tag 0x927c.
TIFFFieldWithTag: Internal error, unknown tag 0x9286.
TIFFFieldWithTag: Internal error, unknown tag 0x9290.
TIFFFieldWithTag: Internal error, unknown tag 0x9291.
TIFFFieldWithTag: Internal error, unknown tag 0x9292.
TIFFFieldWithTag: Internal error, unknown tag 0xa000.
TIFFFieldWithTag: Internal error, unknown tag 0xa001.
TIFFFieldWithTag: Internal error, unknown tag 0xa002.
TIFFFieldWithTag: Internal error, unknown tag 0xa003.
TIFFFieldWithTag: Internal error, unknown tag 0xa004.
TIFFFieldWithTag: Internal error, unknown tag 0xa20b.
TIFFFieldWithTag: Internal error, unknown tag 0xa20c.
TIFFFieldWithTag: Internal error, unknown tag 0xa20e.
TIFFFieldWithTag: Internal error, unknown tag 0xa20f.
TIFFFieldWithTag: Internal error, unknown tag 0xa210.
TIFFFieldWithTag: Internal error, unknown tag 0xa214.
TIFFFieldWithTag: Internal error, unknown tag 0xa215.
TIFFFieldWithTag: Internal error, unknown tag 0xa217.
TIFFFieldWithTag: Internal error, unknown tag 0xa300.
TIFFFieldWithTag: Internal error, unknown tag 0xa301.
TIFFFieldWithTag: Internal error, unknown tag 0xa302.
TIFFFieldWithTag: Internal error, unknown tag 0xa401.
TIFFFieldWithTag: Internal error, unknown tag 0xa402.
TIFFFieldWithTag: Internal error, unknown tag 0xa403.
TIFFFieldWithTag: Internal error, unknown tag 0xa404.
TIFFFieldWithTag: Internal error, unknown tag 0xa405.
TIFFFieldWithTag: Internal error, unknown tag 0xa406.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa408.
TIFFFieldWithTag: Internal error, unknown tag 0xa409.
TIFFFieldWithTag: Internal error, unknown tag 0xa40a.
TIFFFieldWithTag: Internal error, unknown tag 0xa40b.
TIFFFieldWithTag: Internal error, unknown tag 0xa40c.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa407.
TIFFFieldWithTag: Internal error, unknown tag 0xa420.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff77bc92c in FreeImage_GetPixelColor (dib=0x5555557847b0, x=0, 
    y=<optimized out>, value=0x555555554e70 <_start>)
    at Source/FreeImage/PixelAccess.cpp:97
97  Source/FreeImage/PixelAccess.cpp: No such file or directory.
(gdb) bt full
#0  0x00007ffff77bc92c in FreeImage_GetPixelColor (dib=0x5555557847b0, x=0, 
    y=<optimized out>, value=0x555555554e70 <_start>)
    at Source/FreeImage/PixelAccess.cpp:97
        bits = 0x7ffff7e4d1b0 "\377"
#1  0x00005555555551a1 in getPixels (image=0x5555557847b0, pixels1=0x7ffff3c0c010, 
    width1=512, height1=512) at ccc-common.c:122
        rgb1 = 0x555555554e70 <_start>
        t1 = 0x7fffffffe330
        x = 0
        y = 0
#2  0x0000555555555986 in main (argc=2, argv=0x7fffffffe338) at ccc-compress.c:175
        cpmsg = 0x7ffff780f130 "This program uses FreeImage, a free, open source image library supporting all common bitmap formats. See http://freeimage.sourceforge.net for details"
        image_data = 0x5555557847b0
        file_name = 0x7fffffffe5fe "test.tiff"
        file_type = 18
        rgb2 = 0x0
        width = 512
        height = 512
        pixels = 0x7ffff3c0c010
        pixel_luminances = 0x7ffff3a0b010
        pixel_blocks = 0x7ffff354a010
        histogram = <error reading variable histogram (value requires 131072 bytes, which is more than max-value-size)>
        histogram2 = {0 <repeats 128 times>}
---Type <return> to continue, or q <return> to quit---
        histogram3 = {0 <repeats 128 times>}
        lookup_table = {0 <repeats 256 times>}
        lb1 = 0
        raw = <error reading variable raw (Cannot access memory at address 0x0)>
(gdb) continue
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) quit

如果我摆脱所有 FreeImage 库特定代码并初始化我的像素数组,比如说,全部为纯蓝色,那么我不会收到段错误或其他错误或异常。

最佳答案

我在 FreeImage 错误论坛上的一位成员的帮助下发现了这个问题。这是对 FreeImage 文档的误解。我所要做的就是,而不是声明“RGBQUAD *rgb1;”在以下函数中:

void getPixels(FIBITMAP *image, pixel *pixels1, int width1, int height1) {
    for (int y = 0; y < height1; y++) {
        for (int x = 0; x < width1; x++) {
            RGBQUAD *rgb1;
            int pixels_max_size1 = width1*height1*sizeof(pixel);
            if(!FreeImage_GetPixelColor(image, (unsigned) x, (unsigned) y, rgb1)) {
                fprintf(stderr, "FreeImage_GetPixelColor error\n");
                errorlevel = 1;
                return;
            }
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y, pixels_max_size1);
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y);
            if (errorlevel) {
                return;
            }
            t1->r = (uint8_t) (rgb1->rgbRed);
            t1->g = (uint8_t) (rgb1->rgbGreen);
            t1->b = (uint8_t) (rgb1->rgbBlue);*/

            t1->color = ((((rgb1.rgbRed) << 16) & 0xFF0000 ) + (((rgb1.rgbGreen) << 8) & 0x00FF00) + (((rgb1.rgbBlue)) & 0x0000FF)) & 0xFFFFFF;
        }
    }
}

我改为这样做:

void getPixels(FIBITMAP *image, pixel *pixels1, int width1, int height1) {
    for (int y = 0; y < height1; y++) {
        for (int x = 0; x < width1; x++) {
            RGBQUAD rgb1;
            int pixels_max_size1 = width1*height1*sizeof(pixel);
            if(!FreeImage_GetPixelColor(image, (unsigned) x, (unsigned) y, &rgb1)) {
                fprintf(stderr, "FreeImage_GetPixelColor error\n");
                errorlevel = 1;
                return;
            }
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y, pixels_max_size1);
            pixel *t1 = getElement((void *) pixels1, width1, sizeof(pixel), x, y);
            if (errorlevel) {
                return;
            }
            t1->r = (uint8_t) (rgb1->rgbRed);
            t1->g = (uint8_t) (rgb1->rgbGreen);
            t1->b = (uint8_t) (rgb1->rgbBlue);*/

            t1->color = ((((rgb1.rgbRed) << 16) & 0xFF0000 ) + (((rgb1.rgbGreen) << 8) & 0x00FF00) + (((rgb1.rgbBlue)) & 0x0000FF)) & 0xFFFFFF;
    }
    }
}

也就是说,我声明了一个已初始化的 RGBQUAD 局部变量,然后将其地址传递给 FreeImage_GetPixelColor() 。

这个问题现在已经回答/解决了:)

jdb2

关于c - 调用 FreeImage_GetPixelColor() 时出现奇怪的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57117923/

相关文章:

c - 如何将 const 数组或变量数组传递给 C 中的函数?

c - 不兼容的二维指针数组

html - 图片url下载图片而不是显示图片

python - 我编写了我的 Telegram Bot (用Python)提示用户发送图像。如何确保用户只发送图像而不发送其他内容?

python - 从 Python 传递字符串时 PyArg_ParseTuple 的段错误

c++ - vector 中嵌套 vector 的分段故障核心转储

c - Printf 以某种方式改变了一些东西?

c - 为什么 str[5]、str[] = "1234"和 str = malloc(5) 有不同的大小?

image - 谷歌地图静态标记 api 与地址

c++ - MinGW 编译的程序在 64 位 Windows 上崩溃