我一直在用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 生成的 512x512 像素的纯蓝色方块。另外,奇怪的是,当我在代码中将 calloc()s 更改为 malloc()s 时,FreeImage 库似乎没有表现出问题(我使用 calloc() 来初始化我的数据结构。它们是整数和浮点类型的混合,都需要清零)。
我运行在Linux Mint 19.1 Cinnamon x86 64位上,版本为FreeImage库的版本3。
段错误是在 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 %sn It *MUST* be type BMP, JPEG, PNG or TIFFn", FreeImage_GetFormatFromFIF(fif));
printf("Format is type %sn It *MUST* be type BMP, JPEG, PNG or TIFFn", FreeImage_GetFormatFromFIF(fif));
}
printf("%sn", 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 errorn");
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 bugs论坛上的一个成员的帮助下发现了这个问题。这是对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 errorn");
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 errorn");
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