1

I've been working on some image compression C code with the FreeImage library. After having mostly debugged the image compression code, my program now segfaults in the FreeImage library :

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.

I have no idea why I am getting this error. According to GDB the problem may be my accessing an RGBQUAD pointer in the wrong way, but I'm not sure.

In addition, any TIFF file created by the GIMP and supplied to FreeImage generates a huge amount of non-fatal error messages on STDERR. The TIFF file I am supplying as a test for my code is a 512x512px solid blue square generated using the GIMP. Also, strangely, the FreeImage library doesn't appear to manifest the problem when I change the calloc()s to malloc()s in my code ( I use calloc() for the initialization of my data structures. They are a mix of integer and floating point types that all need to be zeroed out ).

I'm running on Linux Mint 19.1 Cinnamon x86 64-bit with version 3 of the FreeImage library.

The segfault is generated in the getPixels() function which is called from main() at the start of the image compression code :

#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);
        }
    }
}

The variable t1 is a pointer to a 2-dimensional array of pixel structs :

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

The segfault, however, occurs before this array is accessed

The expected result would be that the FreeImage_GetPixelColor doesn't segfault. Here is the GDB backtrace :

$ 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

If I get rid of all the FreeImage library specific code and initialize my pixels array, to, say, all solid blue, then I receive no segfault or other errors or exceptions.

jdb2
  • 101
  • 6
  • I know there are some obvious errors in my code, such as using the uint8_t type cast instead of the correct uint32_t type cast, but I didn't think it was relevant to the problem. – jdb2 Jul 19 '19 at 18:34
  • Just to be clear, the FreeImage library blows up when the following statement is encountered in my code : ` if(!FreeImage_GetPixelColor(image, (unsigned) x, (unsigned) y, rgb1)) { fprintf(stderr, "FreeImage_GetPixelColor error\n"); errorlevel = 1; return; } ` – jdb2 Jul 19 '19 at 18:41

1 Answers1

0

I found the problem with the help of a member on the FreeImage bugs forums. It was a misunderstanding of the FreeImage documentation. All I had to do, was, instead of declaring "RGBQUAD *rgb1;" in the following function :

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;
        }
    }
}

I instead do this :

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;
    }
    }
}

That is, I declare an initialized RGBQUAD local variable, and then pass its address to FreeImage_GetPixelColor() .

This question is now answered / solved :)

jdb2

jdb2
  • 101
  • 6