NKK
NKK

Reputation: 13

C Thread Invalid read of size 8 with buffer array

I have the problem, that when I want to assign my buffer array values, there is a segmentation fault Code:

#define BMPHEADER_SIZE 54
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>

// there will be a low level I/O function from the operating system
extern long write(int, const char *, unsigned long);

float zoom      = 1.5;
float quadLimit = 3.0;
char colorLimit = 40;
pthread_mutex_t lock;


typedef struct Complex_s {
    float re;
    float im;
} Complex;

typedef struct {
    int width;
    int height;
    int anfang;
    int ende;
    float imageRelation;
    char *blueGreenRed;
    //char *buffer;
    char ***buffer;
}info1;

// bad, but fast !!!
int intFloor(double x) {
    return (int)(x+100000) - 100000;
}

// count chars until \0 or space or "to long"
int len(char * str) {
    int ddorf=0;
    while (str[ddorf] != '\0' && str[ddorf] != ' ' && ddorf != 40225) ++ddorf;
    return ddorf;
}

// read a positive number from a char array
int str2num(char * str) {
    int result = 0;
    int b = 1;
    int l = len(str);
    int i;
    for(i=1; i<l; ++i) b *= 10;
    for(i=0; i<l; ++i) {
        result += b * (int)(str[i] - '0');
        b /= 10;
    }
    return result;
}

void toRGB(int id, char * blueGreenRed) {
    blueGreenRed[0] = 0;
    blueGreenRed[1] = 0;
    blueGreenRed[2] = 0;
    if ( id == colorLimit ) return;

    float hi,q,t,coeff;

    coeff = 7.0 * (id/(float)colorLimit);
    hi = intFloor(coeff);
    t = coeff - hi;
    q = 1 - t;
    if (hi == 0.0) {
        blueGreenRed[2] = 0;
        blueGreenRed[1] = t*255; //immer mehr green und blau -> dunkelblau zu cyan
        blueGreenRed[0] = t*127 + 128;
    } else if (hi == 1.0) {
        blueGreenRed[2] = t*255; //immer mehr rot -> cyan zu weiss
        blueGreenRed[1] = 255;
        blueGreenRed[0] = 255;
    } else if (hi == 2.0) {
        blueGreenRed[2] = 255;
        blueGreenRed[1] = 255;
        blueGreenRed[0] = q*255; // immer weniger blau -> weiss zu gelb
    } else if (hi == 3.0) {
        blueGreenRed[2] = 255;
        blueGreenRed[1] = q*127 + 128; // immer weniger green -> gelb zu orange
        blueGreenRed[0] = 0;
    } else if (hi == 4.0) {
        blueGreenRed[2] = q*127 + 128; // orange wird dunkler -> orange zu braun
        blueGreenRed[1] = q*63 + 64;
        blueGreenRed[0] = 0;
    } else if (hi == 5.0) {
        blueGreenRed[2] = 128;
        blueGreenRed[1] = 64;
        blueGreenRed[0] = t*128; // mehr blau -> braun zu violett
    } else if (hi == 6.0) {
        blueGreenRed[2] = q*128; // weniger rot und green -> violett wird dunkelblau
        blueGreenRed[1] = q*64;
        blueGreenRed[0] = 128;
    }
}

char* calculatePunkt(int x, int y, int width, int height, float imageRelation, char *blueGreenRed) {

    char iterate=0;
    Complex c    = {0,0};
    Complex newz = {0,0};
    Complex z = {0,0};
    float quad=0;

    c.re = zoom * (-1.0 + imageRelation * ( (x-1.0) / (width-1.0)) );
    c.im = zoom * ( 0.5 - (y-1.0) / (height-1.0) );

    // iterate
    for ( iterate=1; iterate < colorLimit && quad < quadLimit; ++iterate ) {
        quad = z.re * z.re + z.im * z.im;

        newz.re = (z.re * z.re) - (z.im * z.im) + c.re;
        newz.im =  z.re * z.im * 2.0            + c.im;

        z = newz;
    }
    toRGB(iterate, blueGreenRed);

    return blueGreenRed;
}   

void *calculateThread(void *arg){

    info1 *abc =(info1*) arg;
    int x, y;
    int anfang = abc->anfang;
    int ende = abc->ende;
    int width = abc->width;
    int height = abc->height;
    float imageRelation = abc->imageRelation;
    char *blueGreenRed = abc->blueGreenRed;
    char ***buffer = abc->buffer;
    //char *buffer = abc->buffer;

    for (y=anfang; y <= ende; ++y) {    

        for (x=1; x <= width; ++x) {


            char* rgb = calculatePunkt(x, y, width, height, imageRelation, blueGreenRed);
            fprintf(stderr, "test, %d\n", anfang);
            pthread_mutex_lock(&lock);
            //buffer[(y-1)+(height*(x-1))+(height*width*0)] = rgb[0];
            //buffer[(y-1)+(height*(x-1))+(height*width*1)] = rgb[1];
            //buffer[(y-1)+(height*(x-1))+(height*width*2)] = rgb[2];
            buffer[y-1][x-1][0] = 1;
            buffer[y-1][x-1][1] = 1;
            buffer[y-1][x-1][2] = 1;
            pthread_mutex_unlock(&lock);
        }
    }




}   

int main(int argc, char ** argv, char ** envp) {
    int width  = str2num(argv[1]);
    int height = str2num(argv[2]);
    int anzahl_threads = str2num(argv[3]);

    float imageRelation = (float)width/(float)height;
    int i, j, anfang, ende, y;
    char blueGreenRed[3];
    char buffer[height][width][3];
    for(i=0; i<height; i++){
        for(j=0; j<width; j++){
            buffer[i][j][0]=0;
            buffer[i][j][1]=0;
            buffer[i][j][2]=0;
        }
    }       
    //char *buffer = malloc(height*width*3*sizeof(char));
    //*buffer = (char*){ 0 };


    unsigned char info[BMPHEADER_SIZE] = {
                  //size
        'B','M',  0,0,0,0, 0,0, 0,0, 54,0,0,0,
                  //width  //height
        40,0,0,0, 0,0,0,0, 0,0,0,0,  1,0, 24,0,
                  // datasize
        0,0,0,0,  0,0,0,0
    };

    // BMP lines must be of lengths divisible by 4
    char span[4] = "\0\0\0\0";
    int spanBytes = 4 - ((width * 3) % 4);
    if (spanBytes == 4) spanBytes = 0;
    int psize = ((width * 3) + spanBytes) * height;

    *( (int*) &info[2])  = BMPHEADER_SIZE + psize;
    *( (int*) &info[18]) = width;
    *( (int*) &info[22]) = height;
    *( (int*) &info[34]) = psize;

    write(1, (char *) info, BMPHEADER_SIZE);

    struct timeval start, end;
    gettimeofday(&start, 0);
    int interval = height/anzahl_threads;

    info1 *abc = malloc(anzahl_threads*sizeof(info1));;

    pthread_t *thread = malloc(anzahl_threads*sizeof(pthread_t));

    if(pthread_mutex_init(&lock, NULL)){
        fprintf(stderr, "Error initializing mutex\n");
        return 1;
    }
    for(i=0; i<anzahl_threads; i++){

        (abc+i)->width = width;
        (abc+i)->height = height;
        (abc+i)->imageRelation = imageRelation;
        (abc+i)->blueGreenRed = blueGreenRed;
        (abc+i)->buffer = ***buffer;
        //abc->buffer = *buffer;
        anfang = 1+(i*interval);
        (abc+i)->anfang = anfang;
        if(i<(anzahl_threads-1)){
            ende = (i*interval)+interval;
        }
        else{
            ende = height;
        }
        (abc+i)->ende = ende;       
        if (pthread_create(&thread[i], NULL, calculateThread, (void*)(abc+i))) {
            fprintf(stderr, "Error creating thread\n");
            return 1;
        }

    }   

    for(i=0; i<anzahl_threads; i++){
        if (pthread_join(thread[i], NULL)) {
            fprintf(stderr, "Error joining thread\n");
            return 2;
        }
    }
    pthread_mutex_destroy(&lock);

    for(y=1; y<=height; ++y){
        // BMP lines must be of lengths divisible by 4
        write(1, span, spanBytes);
    }   
    write(1, buffer, height*width*3);
    //free(buffer);
    free(thread);
    free(abc);



    gettimeofday(&end, 0);

    unsigned long timediff = ((end.tv_sec*1000000)+end.tv_usec) - ((start.tv_sec*1000000)+start.tv_usec);
    fprintf(stderr, "Gesamtzeit in Mikrosek.: %lu\n", timediff);
    return 0;
}

Valgrind:

==28366== Thread 2:
==28366== Invalid read of size 8
==28366==    at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366==    by 0x4E3F183: start_thread (pthread_create.c:312)
==28366==    by 0x514F37C: clone (clone.S:111)
==28366==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==28366== 
==28366== 
==28366== Process terminating with default action of signal 11 (SIGSEGV)
==28366==  Access not within mapped region at address 0x0
==28366==    at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366==    by 0x4E3F183: start_thread (pthread_create.c:312)
==28366==    by 0x514F37C: clone (clone.S:111)
==28366==  If you believe this happened as a result of a stack
==28366==  overflow in your program's main thread (unlikely but
==28366==  possible), you can try to increase the size of the
==28366==  main thread stack using the --main-stacksize= flag.
==28366==  The main thread stack size used in this run was 8388608.
--28366-- REDIR: 0x50d7d00 (libc.so.6:free) redirected to 0x4c2bd80 (free)
==28366== 
==28366== HEAP SUMMARY:
==28366==     in use at exit: 640 bytes in 4 blocks
==28366==   total heap usage: 4 allocs, 0 frees, 640 bytes allocated
==28366== 
==28366== Searching for pointers to 4 not-freed blocks
==28366== Checked 16,869,264 bytes
==28366== 
==28366== Thread 1:
==28366== 544 bytes in 2 blocks are possibly lost in loss record 3 of 3
==28366==    at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28366==    by 0x4012E14: allocate_dtv (dl-tls.c:296)
==28366==    by 0x4012E14: _dl_allocate_tls (dl-tls.c:460)
==28366==    by 0x4E3FD92: allocate_stack (allocatestack.c:589)
==28366==    by 0x4E3FD92: pthread_create@@GLIBC_2.2.5 (pthread_create.c:500)
==28366==    by 0x40187E: main (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366== 
==28366== LEAK SUMMARY:
==28366==    definitely lost: 0 bytes in 0 blocks
==28366==    indirectly lost: 0 bytes in 0 blocks
==28366==      possibly lost: 544 bytes in 2 blocks
==28366==    still reachable: 96 bytes in 2 blocks
==28366==         suppressed: 0 bytes in 0 blocks
==28366== Reachable blocks (those to which a pointer was found) are not shown.
==28366== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==28366== 
==28366== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==28366== 
==28366== 1 errors in context 1 of 2:
==28366== Thread 2:
==28366== Invalid read of size 8
==28366==    at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366==    by 0x4E3F183: start_thread (pthread_create.c:312)
==28366==    by 0x514F37C: clone (clone.S:111)
==28366==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==28366== 
==28366== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

When I comment the buffer assignment in the thread function, it works. So it has to do something with the buffer, but I don't see the mistake.

Upvotes: 0

Views: 884

Answers (2)

Ian Abbott
Ian Abbott

Reputation: 17403

You are trying to access the data via a pointer to pointer to pointer to char (char ***), but the data is actually an array [height] of array [width] of array [3] of char (char [height][width][3]). A pointer to the first element of this array is a pointer to an array [width] of array [3] of char (char (*)[width][3]). Since width and height are variable, the info1 type cannot contain a member buffer of type char (*)[width][3], so the easiest thing to do is to declare it as a void *:

typedef struct {
    ...
    void *buffer;
    ...
} info1;

In function calculateThread, the original width value is available, so you can declare local variable buffer with the correct type and initialize it:

    char (*buffer)[width][3] = abc->buffer;

In function main, the assignment (abc+i)->buffer = ***buffer; is obviously incorrect as ***buffer is of type char. You want a pointer to the start of the buffer contents, which is just buffer, so change that to:

            (abc+i)->buffer = buffer;

Upvotes: 1

Chris Turner
Chris Turner

Reputation: 8142

This line of code is obviously wrong. The type on the left hand side is a char *** and you're assigning to it a char, with specifically the value of 0 as that is how you initialise buffer at the top of main

(abc+i)->buffer = ***buffer;

ideally you want it to be

(abc+i)->buffer = buffer;

but that won't work as buffer is a 3 dimensional array rather than a char *** and they're not equivalent.

You could either create buffer as a char *** by allocating the various levels or since each thread is only accessing a subset of buffer you could make it a global variable?

Upvotes: 1

Related Questions