2016-05-22 6 views
-1

Ich soll einen Bot schreiben, der Webadressen aus Datei liest und eine GET Anfrage ausführt, die wieder in eine Datei geschrieben wird. Dies funktioniert soweit, aber das Programm endet immer mit einem "Stack Smashing Error". Ich arbeite mit mehreren "Consumer" -Threads, die den Job erledigen, und wenn alle GET Anfragen erledigt sind und der erste Thread fertig ist, wird das Programm beendet.Stack smashing error

Unten ist mein Code:

#include <pthread.h> 
#include <time.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include "Socket/msocket.h" 
/* 
* 
*/ 

#define MAXLINE 512 

typedef struct { 
    char** addr; 
    long head, tail; 
    int full, empty, reading; 
    pthread_mutex_t *mut; 
    pthread_cond_t *notFull, *notEmpty; 
} queue; 

typedef struct { 
    struct queue *q; 
    int tid; 
} arguments; 

int queueSize; 
int elemCount=0; 
int isEmpty; 
char file[MAXLINE]; 

void *readFile(void *args); 
void *consume(void *args); 
char* parseLine(char*); 
char** parseAddr(char*); 
queue *queueInit (int); 
void queueDelete (queue *q); 
void queueAdd (queue *q, char* new); 
void queueDel (queue *q, char** out, int *o); 

/* main function 
    argv[0]: program name (here ./bot) 
    argv[1]: file name (xyz.txt,...) 
    argv[2]: size of queue 
    argv[3]: number of client/consumer threads 
*/ 
int main(int argc, char** argv) { 

    strcpy(file, argv[1]); 
    queueSize = atoi(argv[2]); 
    int maxCli = atoi(argv[3]); 
    printf("-------queueSize: %i--------\n", queueSize); 
    printf("---------maxCli: %i-------\n", maxCli); 
    int j=0; 
    queue *fifo; 
    pthread_t prod, con[maxCli]; 
    struct timeval tv; 

    fifo = queueInit(queueSize); 
    if(fifo == NULL){ 
     printf("queueInit() failed"); 
     exit(1); 
    } 

    gettimeofday(&tv, NULL); 
    double start = (tv.tv_sec) * 1000 + (tv.tv_usec)/1000; 
    pthread_create(&prod, NULL, readFile, fifo); 
    while(j<maxCli){ 

     arguments *threadSet = malloc(sizeof(arguments)); 
     threadSet->q = fifo; 
     threadSet->tid = j+1; 
     pthread_create(&con[j], NULL, consume, threadSet); 
     j++; 
    } 
    j=0; 
    pthread_join(prod, NULL); 
    while(j<maxCli){ 
     pthread_join(con[j], NULL); 
     j++; 
    } 
    double end = (tv.tv_sec) * 1000 + (tv.tv_usec)/1000; 
    printf("time elapsed: %d\n", end-start); 

    printf("----------------threads end----------------\n"); 
    queueDelete(fifo); 

    return (EXIT_SUCCESS); 
} 

void *readFile(void *q){ 
    FILE *fp = fopen(file, "r"); 
    if(fp==NULL){ 
     printf("fopen() failed"); 
     return; 
    } 

    char tmp[MAXLINE]; 
    arguments *threadSet; 
    queue *fifo; 
    int k; 

    fifo = (queue *)q; 

    while(fgets(tmp, MAXLINE, fp) != NULL){ 
     pthread_mutex_lock(fifo->mut); 
     if(fifo->full){ 
      printf("producer: queue FULL\n"); 
      pthread_cond_wait(fifo->notFull, fifo->mut); 
     } 
     strcpy(tmp, parseLine(tmp)); 
     queueAdd(fifo, tmp); 
     elemCount++; 
     printf("producer: added %s\n", tmp); 
     printf("element count: %i\n", elemCount); 

     pthread_mutex_unlock(fifo->mut); 
     pthread_cond_signal(fifo->notEmpty); 

     usleep(100000 + 100000); 
    } 
    fclose(fp); 
    fifo->reading = 0; 
    printf("--------------read end---------------\n"); 
    return(NULL); 
} 

void *consume(void *a){ 
    printf("consume begin\n"); 
    arguments *threadSet; 
    queue *fifo; 
    char* c; 
    int elemNr; 
    int retValue; 

    threadSet = (arguments *)a; 
    fifo = (queue *)threadSet->q; 

    while(1){ 
     pthread_mutex_lock(fifo->mut); 
     //printf("---------------consume begin--------------\n"); 
     if(fifo->empty && !fifo->reading){ 
      printf("end\n"); 
      break; 
     } 
     if(fifo->empty && fifo->reading){ 
      printf("consumer(%i): queue EMPTY\n", threadSet->tid); 
      pthread_cond_wait(fifo->notEmpty, fifo->mut); 
     } 
     if(!fifo->empty){ 
      queueDel(fifo, &c, &elemNr); 
      char fname_a[] = "file_"; 
      char* fname_b = malloc(MAXLINE); 
      snprintf(fname_b, MAXLINE, "<%i>_<%i>.html", elemNr, threadSet->tid); 
      strcat(fname_a, fname_b); 
      printf("%s\n", fname_a); 

      char** args; 
      args = parseAddr(c); 
      if((retValue = askServer(args[0], args[1], fname_a)) < 0){ 
       printf("askServer() failed: %s\n", args[0]); 
       printf("error value: %i\n", retValue); 
       return(NULL); 
      } 
      elemCount--; 
      printf("consumer(%i): picked %s\n", threadSet->tid, c); 
      printf("---------------consume end--------------\n"); 
     } 
     pthread_mutex_unlock(fifo->mut); 
     pthread_cond_signal(fifo->notFull); 
     usleep(200000 + 300000); 
    } 
    printf("end thread: consumer(%i)\n", threadSet->tid); 
    free (threadSet); 
    return(NULL); 
} 

char** parseAddr(char* c){ 
    char* args[2]; 

    char* next = strchr(c, '/'); 
    args[1] = malloc(sizeof(char)*MAXLINE); 
    strcpy(args[1], next); 

    next[0] = '\0'; 
    args[0] = malloc(sizeof(char)*MAXLINE); 
    strcpy(args[0], c); 

    return args; 
} 

char* parseLine(char* c){ 
    char* next = strchr(c, ' '); 
    next[0] = '\0'; 

    char* t = next+1; 
    next = strchr(t, '\n'); 
    if(next != NULL) next[0] = '\0'; 
    strcat(c, t); 

    return c; 
} 

queue *queueInit (int size){ 
    queue *q; 

    q = (queue *)malloc (sizeof (queue)); 
    if (q == NULL) return (NULL); 

    q->addr = malloc(size); 
    int i=0; 
    while(i<size){ 
     q->addr[i] = malloc(sizeof(char)*MAXLINE); 
     i++; 
    } 
    q->empty = 1; 
    q->full = 0; 
    q->reading = 1; 
    q->head = 0; 
    q->tail = 0; 
    q->mut = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t)); 
    pthread_mutex_init (q->mut, NULL); 
    q->notFull = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); 
    pthread_cond_init (q->notFull, NULL); 
    q->notEmpty = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); 
    pthread_cond_init (q->notEmpty, NULL); 

    return (q); 
} 

void queueDelete (queue *q){ 
    pthread_mutex_destroy (q->mut); 
    free (q->mut); 
    pthread_cond_destroy (q->notFull); 
    free (q->notFull); 
    pthread_cond_destroy (q->notEmpty); 
    free (q->notEmpty); 

    int i=0; 
    while(i<queueSize){ 
     free (q->addr[i]); 
     i++; 
    } 
    free (q->addr); 
    free (q); 
} 

void queueAdd (queue *q, char* new){ 
    q->addr[q->tail] = (char*)malloc(sizeof(char)); 
    strcpy(q->addr[q->tail], new); 
    q->tail++; 
    if (q->tail == queueSize) 
     q->tail = 0; 
    if (q->tail == q->head) 
     q->full = 1; 
    q->empty = 0; 

    return; 
} 

void queueDel (queue *q, char **out, int *o){ 
    *out = q->addr[q->head]; 
    *o = q->head+1; 

    q->head++; 
    if (q->head == queueSize) 
     q->head = 0; 
    if (q->head == q->tail) 
     q->empty = 1; 
    q->full = 0; 

    return; 
} 

Fehler Ich erhalte:

* Stapel * erkannt Zerschlagung: ./bot beendet make: *** [run] Abgebrochen

Dies geschieht, nachdem der erste Thread beendet ist. Ich weiß, dass es einen Fehler in der Erinnerung geben muss, aber ich verstehe nicht, warum ich diesen Fehler bekomme. Fehle ich hier etwas? Auch andere Tipps sind erwünscht!

+0

Wie wäre es nur mit wget? – nwp

+0

Warum Zeiger auf die thread-related Elemente der Warteschlangenstruktur verwenden? Warum nicht einfach Instanzen dieser Typen direkt in die Struktur einbetten? Dies ist jedoch nur eine Quelle von Speicherverlust; Im Code sind andere sichtbar. Aber Speicherlecks sind nicht direkt eine Ursache für Stack-Zerschlagung - die Probleme sind etwas tangential zu Ihrem Hauptproblem. –

+0

@nwp weil wir es so machen sollen. Unser Lehrer hat uns eine Klasse für die GET-Anfrage gegeben, die er geschrieben hat, und wir müssen Code um ihn herum sortieren. –

Antwort

1

Ich bin mir ziemlich sicher, dass Sie einen Fehler in parseAddr haben:

char** parseAddr(char* c){ 
    char* args[2]; 
    ... 
    return args; 
} 

Während args[0] und args[1] dynamisch zugewiesen werden, args selbst nicht. Wenn Sie es zurückgeben, wird ein Zeiger auf args tatsächlich zugewiesen. Da das Array args nach dem Beenden der Funktion zerstört wird, führt der Versuch, auf den zurückgegebenen Wert zuzugreifen, zu undefiniertem Verhalten.

Wenn Sie dies tun möchten, übergeben Sie ein Array, das als eines der Argumente für die Funktion ausgefüllt werden soll, und rufen Sie stattdessen die Funktion zum Ausfüllen auf. Sie könnten auch die Array dynamisch zuweisen (zB char** args; args = malloc(sizeof(char*)*2);

Wenn dies nicht hilft, ist es unter valgrind laufen kann Ihre Fehler zu helfen

+0

Jetzt habe ich es so: 'char * args [2];
parseAddr (c, args);
' Und in der Funktion: ' char * next = strchr (c, '/'); printf ("<>>% s \ n", nächstes); args [1] = malloc (Größe von (char) * MAXLINE); strcpy (args [1], nächste); next [0] = '\ 0'; args [0] = malloc (sizeof (char) * MAXLINE); strcpy (args [0], c); ' Noch ein Fehler leider, aber danke für den Hinweis –

0

Es ist wahrscheinlich ein Problem auch hier:..

void queueAdd (queue *q, char* new){ 
    q->addr[q->tail] = (char*)malloc(sizeof(char)); 

sollte geändert werden:

void queueAdd (queue *q, char* new){ 
    q->addr[q->tail] = (char*)malloc(strlen(new)+1); 

Else, die malloc zuzuteilen nur ein Byte vor 'strlen (neu) +1' i Bytes übertragen werden in den zugewiesenen Bereich.

Sie sollen auch diese Art der Adresse Warnung (bereits in einer anderen Antwort über diese erwähnt):

thread.c: In function ‘parseAddr’: 
thread.c:189:5: warning: function returns address of local variable [-Wreturn-local-addr] 
    return args; 
    ^

eine kurze Beschreibung Ihrer Umgebung geben kann auch Menschen helfen, Ihr Problem zu lösen.

+0

Erste Tipp nicht gemacht, aber ich sehe, dass ich es sowieso ändern sollte. Wird diese Warnung bald untersuchen. Was meinst du mit Umwelt? –

+0

Umgebung = Ihre Plattform und Compiler/Linker. – jb07

+0

OS ist Linux Mint, ich schreibe in NetBeans/Notepaddqq und benutze ein Makefile, um alles über das Terminal zu kompilieren (gcc -o bot bot.c). Ich kann das Makefile hier posten, aber ich denke nicht, dass das mit dem Fehler verbunden ist, den ich bekomme –