Search code examples
clinuxgccsegmentation-faulttga

libtga weird Segmentation fault


I didn't want to reinvent the wheel, so I downloaded libtga which seemed to have a convenient and simple API. Building was easy, but I stumbled upon a weird segmentation fault I can not explain. A small example:

#include <stdio.h>
#include "tga.h"
#define TEST

int main()
{
    TGA *tga;
    TGAData data;

    tga = TGAOpen("test.tga", "r");
    if(!tga || tga->last != TGA_OK) 
    { printf("TGAOpen failed\n"); return 1; }
    if(TGAReadImage(tga, &data) != TGA_OK)
    { printf("TGAReadImage failed\n"); return 1; }
    TGAHeader *header = &tga->hdr;
    printf("image dimensions:\n width: %d\t height:%d\t depth:%d bpp\n", 
           header->width, header->height, header->depth);
    tbyte *img = data.img_data;

    if (img== NULL)
    {
        printf("Pointer wrong\n");
        return 1;            
    }
    printf("pointer: %p\n", img);

    printf("test %hhu\n", img[0]);

#ifdef TEST    
    for(int i=0; i<header->height; i++)
    {
        for(int j=0; j<header->width; j++)
        {
            int index = 4*(i*header->width + j);
            printf("%3d %3d %3d %3d | ", img[index], img[index+1], img[index+2], img[index+3]);
        }
        printf("\n");
    }
#endif
    TGAClose(tga);
    return 0;
}

I compile the program with: gcc -g --std=c99 -O0 tgatest.c -L./lib -ltga -I./include

Now, if "TEST" is defined everything works fine and the values for each pixel are printed to stdout (I use a 4x4 image). If I don't define "TEST" it throws a segmentation fault at line

printf("test %hhu\n", img[0]);

I don't understand why. Debugging shows that "img" is "Address 0x1 out of bounds", but with "TEST" it is a valid address. Any suggestions how to further investigate this? I thought the compiler may optimize things away, but -O0 doesn't change anything. Same for the --std=c99.


Solution

  • According to the tgalib documentation you need to set TGA_IMAGE_DATA on data->flags before calling TGAReadImage to ensure that the image data will be read. It's possible that in the TEST build the garbage on the stack under the data variable happens to have this bit set, but not in the other build.

    Adding a line like the following immediately before the TGAReadImage call should do the trick:

    data.flags = TGA_IMAGE_DATA;