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

时间:2019-07-19 18:28:48

标签: 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上生成大量非致命错误消息。我为测试我的代码而提供的TIFF文件是使用GIMP生成的512x512px蓝色实心正方形。而且,奇怪的是,当我在代码中将calloc()更改为malloc()时,FreeImage库似乎没有表现出问题(我使用calloc()初始化数据结构。它们混合了都需要清零的整数和浮点类型。)

我正在使用FreeImage库的版本3在Linux Mint 19.1 Cinnamon x86 64位上运行。

segfault是在getPixels()函数中生成的,该函数在图像压缩代码的开头从main()调用:

#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库特定的代码,并将我的pixels数组初始化为全蓝色,那么我就不会收到段错误或其他错误或异常。

1 个答案:

答案 0 :(得分:0)

我在FreeImage bug论坛上的一位成员的帮助下发现了问题。这是对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