2010-12-06 5 views
1

EDIT3: Il apparaît dans un nouveau thread chaque fois qu'il est nécessaire, "input" est une copie d'un char * qui est libéré à l'intérieur. Supposons que les fonctions cURL sont thread safe.Cette fonction est-elle parfaitement sûre pour les threads?

EDIT4: Supposons que toutes les fonctions non visibles sont sécurisées par les threads.

static void *Com_GoogleTranslate(void* input) { 

CURL *easy_handle; 
char *pos1, *pos2, url[1024], final[1024], inlang[8], outlang[8], *encoded; 
const int const_strlen = strlen("\"translatedText\":\""); 
struct GoogleMem chunk; 

pthread_mutex_lock(&GoogleMessage_mutex); 
    // 'auto' is really empty in google API: 
    if (!strcmp(clu.translateIn->string, "auto")) 
    strcpy(inlang, ""); 
    else    
    strcpy(inlang, clu.translateIn->string); 

    if (!strcmp(clu.translateOut->string, "auto")) 
    strcpy(outlang, ""); 
    else    
    strcpy(outlang, clu.translateOut->string); 
pthread_mutex_unlock(&GoogleMessage_mutex); 

// Build the URL 
url[0] = '\0'; 
strcat(url, "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q="); 

// Encode input into URL formatting 
encoded = url_encode((char*)input); 
if (!encoded) return 0; 

strcat(url, encoded); 
strcat(url, "&langpair="); 
strcat(url, inlang); 
strcat(url, "|"); 
strcat(url, outlang); 

chunk.memory = malloc(1); // realloc grows it at Com_GoogleTranslateMem() 
if (!chunk.memory) return 0; 
chunk.size = 0; // no data yet 

// cURL initialization for this sub-session: 
easy_handle = qcurl_easy_init(); 

// ioq3-urt: was needed on https:// (v2 API) attempts when using GnuTLS 
//qcurl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 3); 

// set URL: 
qcurl_easy_setopt(easy_handle, CURLOPT_URL, url); 

// ioq3-urt: required for multithreading according to cURL doc. 
qcurl_easy_setopt(easy_handle, CURLOPT_NOSIGNAL, 1); 

// ioq3-urt: skip peer verification; required for google translate when SSL was used 
//qcurl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); 

// send all data to this function 
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, Com_GoogleTranslateMem); 

// we pass our 'chunk' struct to the callback function: 
qcurl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *)&chunk); 

// some servers don't like requests that are made without a user-agent field, so we provide one: 
qcurl_easy_setopt(easy_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); 

// ioq3-urt: Required by Google Translate terms: 
qcurl_easy_setopt(easy_handle, CURLOPT_REFERER, "ioq3-urt"); 

// fetch it 
qcurl_easy_perform(easy_handle); 

// cleanup curl stuff 
qcurl_easy_cleanup(easy_handle); 

/* 
    Now chunk.memory points to a memory block that is chunk.size 
    bytes big and contains the remote file. 

    Nothing has yet deallocated that data, hence free() is used at the end. 
*/ 

if (!chunk.size) { 
    pthread_mutex_lock(&GoogleMessage_mutex); 
    sprintf(GoogleMessage.message, "Translation: no data received from Google\n"); 
    GoogleMessage.new_message = qtrue; 
    pthread_mutex_unlock(&GoogleMessage_mutex); 
    // Free up memory (same with the end) 
    if(chunk.memory) free(chunk.memory); 
    free(encoded); 
    free(input); 
    return 0; 
} 

if ((pos1 = strstr(chunk.memory, "\"translatedText\":\""))) { // Make sure we use a valid file: 

    pos2 = strstr(pos1 + const_strlen, "\""); // position translated text ends 

    // Build the translated text: 
    final[0] = '\0'; 
    strncat(final, pos1 + const_strlen, strlen(pos1) - (strlen(pos2) + const_strlen)); 

    // Final printing of the translated text: 
    pthread_mutex_lock(&GoogleMessage_mutex); 
    sprintf(GoogleMessage.message, "^2Translated^7: ^3%s\n", final); 
    GoogleMessage.new_message = qtrue; 
    pthread_mutex_unlock(&GoogleMessage_mutex);  
    #ifdef BUILD_FREETYPE 
    TTF_Find_Slot(final, clu.TTF_MessageMaxTime->integer); 
    #endif 

} else { 
    pthread_mutex_lock(&GoogleMessage_mutex); 
    sprintf(GoogleMessage.message, "Translation: no valid translation file received from Google\n"); 
    GoogleMessage.new_message = qtrue; 
    pthread_mutex_unlock(&GoogleMessage_mutex); 
} 

// Free allocated memory 
if(chunk.memory) free(chunk.memory); 
free(encoded); 
free(input); 
return 0; 
} 

Je reçois un comportement instable sur certains système seulement et alors que je soupçonne que son matériel douteux (Intel OpenGL?), Je voudrais savoir si je manque quelque chose.

EDIT: Supposons que cURL est thread-safe en lui-même.

EDIT2: "entrée" est une nouvelle copie qui est libérée dans ce fil de discussion.

+0

Quelle est la connexion à Intel et OpenGL? –

+0

Il fonctionne dans un jeu (qui s'exécute dans un contexte SDL OpenGL). La fonction n'appelle pas directement ou indirectement aucune fonction OpenGL (qui est intrinsèquement dangereuse n'importe où), cependant, Intel dans OpenGL a une réputation horrible, horrible, horrible pour les programmeurs OpenGL que je ne peux m'empêcher de suspecter même dans ce cas. –

Répondre

1

Il me semble thread sûr tant que toutes les fonctions qu'il appelle en dehors des sections protégées mutex sont eux-mêmes thread sécurisé.

Il existe cependant une question sur la sécurité des filetages de malloc. Voir this question.

+0

Eh bien, je ne fais que compiler sur gcc donc .. –

+0

Intéressant sur malloc .. rend multithreading beaucoup plus effrayant ... Ces API OpenMP etc sont pratiques après tout .. (pour faire la plupart de ces choses automatiquement) –

1

Ce problème n'est pas lié à la sécurité des threads, mais il y a une chose qui ressort comme un problème potentiel. La ligne de code suivante ne vérifie pas pour une recherche réussie:

pos2 = strstr(pos1 + const_strlen, "\""); // position translated text ends 

Si la valeur chunk.memory ne contenait pas une autre double citation suivante la valeur "translatedText":", il serait nul et la strlen() ultérieure sur cette valeur à l'intérieur du strncat entraînerait probablement une violation d'accès. Au minimum, il ne devrait pas être inutile d'ajouter un assert pour vérifier qu'il réussit toujours. Mais je ne sais pas ce que font les autres fonctions. S'ils garantissent que la double citation est dans la chaîne, c'est un non-problème. De plus, à partir d'un problème «Je ne sais rien au sujet des données impliquées», il y a les suppositions aveugles sur les longueurs de chaînes ajustées dans les tampons 1024. Du point de vue du codage défensif, des vérifications supplémentaires sur ces appels pourraient ne pas nuire.

Sinon, je suis d'accord (+1) avec JeremyP qu'il semble thread-safe basé sur le code donné.

Questions connexes