Exotic
Exotic

Reputation: 57

C: free(): invalid pointer Aborted (core dumped) error

I am not sure why I am getting this error, I am running a steganography program which takes in a PPM file and allows a user to encode a message into the PPM file and it I tried to debug in valgrind and the error occurs:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

struct PPM {
    char *comments;
    char *ppmname;
    unsigned int width, height, max;
    unsigned int size;
    struct Pixel**pixels;

}ppm;

struct Pixel {
    int r, g, b;
}Pixel;

static int *decimalToBinary(const char *message, unsigned int msgSize);
struct PPM * getPPM(FILE * f);
struct PPM *encode(struct PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(struct PPM * im);

int main(int argc, char *argv[]){
    FILE * fin = fopen("home-cat.ppm", "r");

    if(fin == NULL) {
        perror("Cannot open file");
        exit(1);
    }

    struct PPM *p = getPPM(fin);
    struct PPM *g = encode(p, "test", 5, 2);
    showPPM(g);

    free(p->comments);
    free(p);



    return 0;
}

struct PPM * getPPM(FILE * f) {

    ppm.comments = (char *)calloc(70,sizeof(char));
    ppm.ppmname = (char *)calloc(3,sizeof(char));
    fscanf(f, "%s", ppm.ppmname);

    fgetc(f);
    fgets(ppm.comments, 70, f);
    fscanf(f, "%d %d", &ppm.width, &ppm.height);

    fscanf(f, "%d", &ppm.max);
    ppm.size = ppm.width * ppm.height;
    ppm.pixels = (struct Pixel**)malloc(ppm.width * sizeof(struct Pixel));

    for (int i=0; i<ppm.width; i++) {
        ppm.pixels[i] = (struct Pixel*)malloc(ppm.height*sizeof(struct Pixel));
    }

    for (int i=0; i<ppm.width; i++) {
        for (int j=0; j<ppm.height; j++) {
            fscanf(f, "%d %d %d", &ppm.pixels[i][j].r, &ppm.pixels[i][j].g, &ppm.pixels[i][j].b);
        }
    } 
    return &ppm;
}

void showPPM(struct PPM * im) {
    printf("%s\n", ppm.ppmname);
    printf("%s", ppm.comments);
    printf("%d %d\n", ppm.width, ppm.height);
    printf("%d\n", ppm.max);

    for (int i=0; i<ppm.width; i++) {
        for (int j=0; j<ppm.height; j++){
            printf("%d %d %d\n", ppm.pixels[i][j].r, ppm.pixels[i][j].g, ppm.pixels[i][j].b);
        }
    }
}

struct PPM *encode(struct PPM *im, char *message, unsigned int mSize, unsigned int secret) {
    int *binaryMessage = decimalToBinary(message, mSize);
    int i, j, k;
    bool unique;
    srand(secret);
    int used[40]; memset(used, -1, sizeof(used)); // might have the last two args backwards... I always forget lol
    for(i = 0; i < 39; i+=3) {
        // determine next pixel based on the user's secret (srand)
        // and without ovewrwriting a previous hidden message
        do {
            unique = true;
            j = rand() % 3; // get new number and then check if it's unique
            for(k = 0; k < i; k++) if (used[i] == j) {unique = false; break;}
        } while(!unique);
        im->pixels[j]->r = im->pixels[j]->r & ~1 | binaryMessage[i+0]; // ~1 is 11111110
        im->pixels[j]->g = im->pixels[j]->g & ~1 | binaryMessage[i+1]; // anding keeps the first 7 and clears the last
        im->pixels[j]->b = im->pixels[j]->b & ~1 | binaryMessage[i+2]; // oring will set it if the binaryMessage is set
    }
        // should make a function...
        do {
            unique = true;
            j = rand() % 3; // get new number and then check if it's unique
            for(int k = 0; k < 39; k++) if (used[i] == j) {unique = false; break;}
        } while(!unique);
    im->pixels[j]->r = im->pixels[j]->r & ~1 | binaryMessage[39]; // last bit
    free(binaryMessage);
    return im;
}

static int *decimalToBinary(const char *message, unsigned int length) {
    /*
     * malloc is used here instead of [] notation to allocate memory,
     * because defining the variable with [] will make its scope
     * limited to this function only. Since we want to access this
     * array later on, we use malloc to assign space in the memory
     * for it so we can access it using a pointer later on.
     */
    int k = 0, i, j;
    unsigned int c;
    unsigned int *binary = malloc(8 * length * sizeof(int));

    for(i = 0; i < length; i++) {
        c = message[i];
        for(j = 7; j >= 0; j--,k++) {
            /*
             * We check here if the jth bit of the number is 1 or 0
             * using the bit operator &. If it is 1, it will return
             * 1 because 1 & 1 will be true. Otherwise 0.
             */
            if((c >> j) & 1)
                binary[k] = 1;
            else
                binary[k] = 0;
        }
    }
    return binary;
}

I was not sure why it occurred so I ran the error inside valgrind because I read online that it is a very useful debugger however I still cannot understand what the trace of the problem is. Here is the error report in valgrind:

==2066== Invalid free() / delete / delete[] / realloc()
==2066==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066==    by 0x108B14: main (in /home/ziyad/test12)
==2066==  Address 0x30a060 is 0 bytes inside data symbol "ppm"
==2066== 
==2066== 
==2066== HEAP SUMMARY:
==2066==     in use at exit: 2,150,955 bytes in 515 blocks
==2066==   total heap usage: 519 allocs, 5 frees, 2,156,305 bytes allocated
==2066== 
==2066== 3 bytes in 1 blocks are still reachable in loss record 1 of 4
==2066==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066==    by 0x108B4D: getPPM (in /home/ziyad/test12)
==2066==    by 0x108AC8: main (in /home/ziyad/test12)
==2066== 
==2066== 552 bytes in 1 blocks are still reachable in loss record 2 of 4
==2066==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066==    by 0x4EBAE49: __fopen_internal (iofopen.c:65)
==2066==    by 0x4EBAE49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==2066==    by 0x108A9B: main (in /home/ziyad/test12)
==2066== 
==2066== 6,144 bytes in 1 blocks are still reachable in loss record 3 of 4
==2066==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066==    by 0x108C0E: getPPM (in /home/ziyad/test12)
==2066==    by 0x108AC8: main (in /home/ziyad/test12)
==2066== 
==2066== 2,144,256 bytes in 512 blocks are still reachable in loss record 4 of 4
==2066==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2066==    by 0x108C53: getPPM (in /home/ziyad/test12)
==2066==    by 0x108AC8: main (in /home/ziyad/test12)
==2066== 
==2066== LEAK SUMMARY:
==2066==    definitely lost: 0 bytes in 0 blocks
==2066==    indirectly lost: 0 bytes in 0 blocks
==2066==      possibly lost: 0 bytes in 0 blocks
==2066==    still reachable: 2,150,955 bytes in 515 blocks
==2066==         suppressed: 0 bytes in 0 blocks
==2066== 
==2066== For counts of detected and suppressed errors, rerun with: -v
==2066== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Upvotes: 1

Views: 1491

Answers (1)

Nikos C.
Nikos C.

Reputation: 51832

ppm is a stack object, not a heap-allocated one. You should not free it. You must only call free() on pointers previously returned by malloc() or calloc(). This is not the case here, so don't free() it.

Upvotes: 2

Related Questions