0

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.

the_summer
  • 439
  • 3
  • 10
  • I would say because TEST is put on the stack (unlikely but compilers are weird) and img[0] is looking to the stack for it's value, being img[0] appears to be null it's grabbing TEST's value instead? What does `printf("test %hhu\n", img[0]);` actually result in when TEST is defined? – JasonSec May 14 '14 at 18:32
  • You should check your pointers before use. You might have undefined pointers. If that seems to work with TEST it's just a luck! – daouzli May 14 '14 at 18:34
  • If you want to reinvent the wheel you should interpret yourself Targa images. It is easy. – daouzli May 14 '14 at 18:35
  • @JasonSec The TEST-thing is just here to make the example as concise as possible. The same problem appeared in the program where I wanted to use the library. – the_summer May 14 '14 at 19:21
  • Okay, without seeing the ACTUAL program with the ACTUAL output it's hard to say whether this is correct or not BUT, it would appear daouzli is correct you appear to have undefined pointers, by definition undefined pointers point to undefined locations if all the stars line up correctly and the memory is mapped JUST SO it'll go through fine reading off some garbage data otherwise it'll crash. Fix the root of the problem (undefined pointers) – JasonSec May 14 '14 at 19:24
  • @daouzli Ok. I added a simple pointer test. The img-pointer is not NULL, but still causes a seg-fault. If I look at the library source of the read-function, it only has one malloc-call and checks for a NULL-pointer. So in my understanding the address should be valid (if it is not NULL). That's why I don't understand my results. – the_summer May 14 '14 at 19:27
  • @JasonSec That is what I am trying to do. The memory for the pointer to the image data is allocated by the TGAReadImage-function. It uses malloc, thus it should be either NULL or a valid memory address. Is it possible that the program terminates before the printf command has finished execution, so that it tries to access invalid memory? – the_summer May 14 '14 at 19:31
  • Your error checks (the `if (... != TGA_OK)` blocks) have no bodies, so execution just continues even if an error occurs. If any of those checks indicate an error, you need to abort, e.g. by putting something like `return 1;` in the bodies of those blocks. – nobody May 14 '14 at 19:38
  • @AndrewMedico Yes, I am sorry I didn't mention that. It passes both checks. I just tried to leave it to make the code blocks shorter. I edited it. – the_summer May 14 '14 at 19:42
  • 2
    The example (http://tgalib.sourceforge.net/api/overview.html) implies that 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. – nobody May 14 '14 at 19:48
  • @AndrewMedico You are right. It was the missing flag. Now I know it's not me being stupid. It's only me not being able to read properly (not sure which is worse). Do you want to write the answer, or should I? – the_summer May 14 '14 at 19:53

1 Answers1

3

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;
nobody
  • 19,814
  • 17
  • 56
  • 77