Unerklärlicher Fehler in meinem Programm - wer kann helfen?
-
Hallo zusammen.
Ich suche jetzt schon seit 2 Wochen an einem Fehler in meinem Programm und finde einfach nichts. Ich habe schon alle erdenklichen Debugging-Schritte und Abstraktionen versucht, doch nichts hat geholfen. Ich konnte das Programm jetzt so stark vom Code her abstrahieren, dass ich den Code nun posten kann, da er von MySQL-Datenbanken und sonstiger Umgebung unabhängig ist. Dabei habe ich alle Werte/Intervalle etc exakt so gesetzt, dass der Fehler so schnell wie möglich kommt.
Der Fehler lautet "Speicherzugriffsverletzung" und tritt willkürlich, jedoch generell innerhalb von wenigen Sekunden auf.
Ich verwende Linux und den GCC Compiler. Die Packages libcurl und pthread werden verwendet.
Das Programm hat im Grunde folgende Aufgabe:
- Alle 60 (hier 5) Sekunden einen Thread pwb_neuer_durchlauf(). Dieser garantiert, dass der Abstand genau 60 Sekunden ist.
- Dieser Thread ruft alle Server aus einer MySQL-Datenbank ab (hier nicht) und startet pro Eintrag einen Thread pwb_checking().
- pwb_checking() ruft die Webseite (übergebener Parameter) auf und schaut per http_call(), ob diese Erreichbar ist und schreibt seine Erkenntnisse in die Datenbank (hier nicht).
- In meinem Originalsource habe ich auch bereits versucht, alle pwb_checking() Threads zu joinen, da ich die Vermutung hatte, dass durch das Beenden von pwb_neuer_durchlauf() irgendwelche Ressourcen von pwb_checking() wieder freigegeben werden. Auch keinen Erfolg.Es folgt mein sehr stark abstrahierter und fehlererhaltender Code. Könnt ihr den Fehler reproduzieren oder mir Tipps geben? Bitte um Hilfe, ich verzweifel langsam daran...
Gruß
blackdrake#include <stdlib.h> // free, malloc, atoi, exit, EXIT_SUCCESS, EXIT_FAILURE, setenv #include <pthread.h> // pthread_attr_init, PTHREAD_CREATE_DETACHED, pthread_attr_setdetachstate, pthread_create, pthread_attr_destroy #include <signal.h> #include <curl/curl.h> #include <string.h> #ifdef __cplusplus #include <unistd.h> // sleep() #endif #ifndef __cplusplus #include <stdbool.h> // Typ "bool" #endif struct meinserver { uint id; char* url; int downtime; }; static void async_function_call( void* (*start_routine)(void*), void* arg ) { pthread_t mythread; // Zu Testzwecken nicht Detached int rc = pthread_create(&mythread, NULL, start_routine, arg); if (rc != 0) { printf("pthread_create: '%d'\n", rc); } return; } //******************************************************************************************** // // OFFIZIELLER CODE VON CURL, hier kann kein Fehler drinnen sein #include <curl/types.h> #include <curl/easy.h> struct MemoryStruct { char *memory; size_t size; }; static void *myrealloc(void *ptr, size_t size) { /* There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here */ if(ptr) return realloc(ptr, size); else return malloc(size); } static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)data; #ifndef __cplusplus mem->memory = myrealloc(mem->memory, mem->size + realsize + 1); #else mem->memory = (char*) myrealloc(mem->memory, mem->size + realsize + 1); #endif if (mem->memory) { memcpy(&(mem->memory[mem->size]), ptr, realsize); mem->size += realsize; mem->memory[mem->size] = 0; } return realsize; } // *** ENDE CURL CODE *** // Code von einem offiziellen Example abgeleitet, Fehler unwahrscheinlich static bool http_call (const char* url) { printf("Calling URL: '%s'\n", url); CURL *curl; curl = curl_easy_init(); if (curl) { // URL übergeben curl_easy_setopt(curl, CURLOPT_URL, url); // Pufferoptionen char errorBuffer[CURL_ERROR_SIZE]; curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); struct MemoryStruct chunk; chunk.memory = NULL; chunk.size = 0; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // Der Cast ist für'n Arsch // Benutzerdefinierter User-Agent-Name curl_easy_setopt(curl, CURLOPT_USERAGENT, "Hello World Browser"); // Einen Timeout setzen curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1); // Einen HTTP-Fehler-Statuscode beachten curl_easy_setopt(curl, CURLOPT_FAILONERROR, true); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true); curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE, false); // Abfrage ausführen und Resultat speichern CURLcode res; res = curl_easy_perform(curl); // !! Wäre diese Zeile weg, käme der Fehler nicht. Aber: http_call() funktioniert alleine korrekt. char *buffer = chunk.memory; // Alias printf(buffer); printf("\n"); fflush(stdout); // Clean up curl_easy_cleanup(curl); // Alles OK? if (res == CURLE_OK) { printf("URL successfully entered.\n"); if (buffer != "\0") { printf("There was an output (see next line).\n"); printf(buffer); // Bei snprintf würde der Puffer sonst platzen printf("\n"); } else { printf("There was no output.\n"); } return true; } else { printf("Error while calling URL '%s': [%d] - '%s'\n", url, res, errorBuffer); return false; } } else { return false; } } static char* strcombine(const char* str1, const char* str2) { #ifndef __cplusplus char *newstr = malloc(strlen(str1)+strlen(str2)+1); #else char *newstr = (char*)malloc(strlen(str1)+strlen(str2)+1); #endif if (newstr == NULL) { printf("Malloc-Error at strcombine()!\n"); return NULL; } memcpy(newstr, str1, strlen(str1)+1); strcat(newstr, str2); return newstr; } const char* CHECKING_APPENDIX = "startchecking.php"; static void* pwb_checking(void* data) { // Lese die übergebene Struktur aus struct meinserver *k = (struct meinserver*)data; printf("Start checking of system #%d\n", k->id); char* completeurl = strcombine(k->url, CHECKING_APPENDIX); if (completeurl == NULL) { return NULL; } printf(completeurl); printf("\n"); fflush(stdout); if (http_call(completeurl)) { printf("HTTP CALL OK\n"); } else { printf("HTTP CALL BAD\n"); } free(completeurl); // malloc() von strcombine() wieder freigeben free(k->url); // malloc() von strclone() wieder freigeben printf("Stop checking of system #%d\n", k->id); free(k); // malloc() von pwb_neuer_durchlauf() wieder freigeben return NULL; } static char* strclone(const char* str) { char *newstr = malloc(strlen(str)+1); if (newstr == NULL) { printf("Malloc-Error at strclone()!\n"); return NULL; } memcpy(newstr, str, strlen(str)+1); return newstr; } static void* pwb_neuer_durchlauf(void* data) { // Zu Demonstrationszwecken stark abstrahiert, Fehlererhaltend // Die Werte "Fake-Test" und "2000" kommen eigentlich aus einer DB, sind also lokale Variablen in Form von MYSQL_ROW row[...], werden aber korrekt in die Struktur k kopiert, nicht referenziert. int i; for (i = 0; i<10; i++) { struct meinserver *k = malloc(sizeof *k); if (k == NULL) { printf("Malloc-Error at pwb_neuer_durchlauf()!\n"); return NULL; } k->id = i; k->url = strclone("http://www.viathinksoft.de/fake_test/"); // String einzigartig machen, damit der Pointer nicht ungültig wird, wenn die Funktion zuende ist if (k->url == NULL) { return NULL; } k->downtime = atoi("2000"); async_function_call(pwb_checking, k); // !! Wäre hier ein serieller statt asynchroner Aufruf, dann wäre kein Fehler... wieso? } // In diesem Beispiel kein Join der Threads pwb_checking() return NULL; } int main(void) { while (true) { printf("-----------------------\n"); async_function_call(pwb_neuer_durchlauf, NULL); sleep(5); } return EXIT_SUCCESS; }
-
was in diese richtung vielleicht?
http://curl.haxx.se/mail/lib-2007-04/0128.html
http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading
-
curlnichtthreadsafe? schrieb:
was in diese richtung vielleicht?
http://curl.haxx.se/mail/lib-2007-04/0128.html
http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threadingNö, wieso?
libcurl is completely thread safe, except for two issues ...
Wie ja oben zu sehen ist, share ich keine Handles oder ähnliches.