C Thread使用缓冲区数组读取大小为8的无效内容

时间:2017-05-17 14:30:59

标签: c multithreading valgrind

我遇到的问题是,当我想分配缓冲区数组值时,会出现分段错误 代码:

#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)

当我在线程函数中注释缓冲区赋值时,它可以工作。所以它必须对缓冲区做一些事情,但我没有看到错误。

2 个答案:

答案 0 :(得分:1)

这行代码显然是错误的。左侧的类型为char ***,您为其分配char,特别是0的值,因为这是您初始化buffer的方式在main

的顶部
(abc+i)->buffer = ***buffer;

理想情况下,你希望它是

(abc+i)->buffer = buffer;

但由于buffer不是{3}而是char ***,因此它不会起作用。

您可以通过分配各个级别来创建buffer作为char ***,或者因为每个线程只访问buffer的子集,您可以将其设为全局变量吗?

答案 1 :(得分:1)

您正尝试通过指向charchar ***)指针的指针来访问数据,但数据实际上是数组[{{{height]的数组1 {}} widthchar)的数组[3]。指向此数组的第一个元素的指针是指向char [height][width][3]width)的数组[3]的数组[char]的指针。由于char (*)[width][3]width是可变的,height类型不能包含info1类型的成员buffer,因此最简单的做法是将其声明为char (*)[width][3]

void *

在函数typedef struct { ... void *buffer; ... } info1; 中,原始calculateThread值可用,因此您可以使用正确的类型声明局部变量width并初始化它:

buffer

在功能 char (*buffer)[width][3] = abc->buffer; 中,作业main显然不正确,因为(abc+i)->buffer = ***buffer;的类型为***buffer。你想要一个指向缓冲区内容开头的指针,它只是char,所以把它改为:

buffer