-
-
Couldn't load subscription status.
- Fork 6.9k
Description
I did this
I have a multi threaded application running on Free BSD on a i386 machine out of which in the problem scenario only one thread is active which is waking up every 10 seconds and tries to do a curl_easy_perform() which fails as the DNS resolution fails (for an invalid address like https://abcd.net).
None of the other 3 threads interact with the curl library calls .
If I leave the system in this state for long time(ranging from 20 -30 hours ) ,
1- I see the one of the threads (which is supposed to be waiting in an event loop and do nothing ) gets segmentation fault .
2- Sometimes the kernel kills the process as the process overruns it's RLIMIT.
"/kernel: Process (1954,server-connect) attempted to exceed RLIMIT_DATA: attempted 131092 KB Max 131072 KB"
3 - I have also tried adding curl_global_cleanup() after curl_easy_cleanup() but result was the same .
4- The same application is running on another Octeon based platform running the same OS and there also I see the same results .
Code
static size_t
write_data_in_mem (void *buffer, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct memStruct *in_mem = (struct memStruct *) userp;
in_mem->buff = realloc(in_mem->buff, in_mem->buff_size + realsize + 1);
if (in_mem->buff == NULL) {
syslog(LOG_ERR, "failed to allocate %d bytes for buffer",
realsize+1);
return 0;
}
bzero(&(in_mem->buff[in_mem->buff_size - 1]), realsize+1);
memcpy(&(in_mem->buff[in_mem->buff_size - 1]), buffer, realsize);
in_mem->buff_size += realsize;
in_mem->buff[in_mem->buff_size] = 0;
return realsize;
}
static CURL*
setup_curl_options (char *login_passwd, void *write_func,
void *hdrdata, void *write_data,
char *server_url)
{
CURL *curl_handle = NULL;
object_t *obj = get_object();
long port = obj->curr_port;
unsigned char *cert = obj->curr_cert;
boolean is_https = FALSE;
char *real_url = NULL;
curl_handle = curl_easy_init();
if (!curl_handle) {
PRINT("failed to initialize curl obj");
return NULL;
}
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10L);
if (strstr(server_url, "https://") != NULL) {
is_https = TRUE;
curl_easy_setopt(curl_handle, CURLOPT_CAINFO, obj->ca_cert_file);
}
if (is_https ==TRUE) {
/* SSL options */
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER , 1);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST , 2);
}
/* providing login/passwd */
curl_easy_setopt(curl_handle, CURLOPT_USERPWD, login_passwd);
/* send the output to particular function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_func);
/* pass structure to write function */
curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)hdrdata);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)write_data);
if (NULL != (real_url = get_complete_url_str(server_url, is_https))) {
curl_easy_setopt(curl_handle, CURLOPT_URL, real_url);
free(real_url);
} else {
curl_easy_setopt(curl_handle, CURLOPT_URL, server_url);
}
PRINT("Current Port:%ld", port);
if (port) {
curl_easy_setopt(curl_handle, CURLOPT_PORT, port);
}
return curl_handle;
}
int contact_server (const char* name, char *login_passwd, char * server_url )
{
CURL *curl_handle = NULL;
CURLcode res = CURLE_COULDNT_CONNECT;
struct memStruct header = {NULL, 0};
struct memStruct body = {NULL, 0};
long resp_code = 0;
int retval = -1;
/* init buffer to save server response */
header.buff = calloc(1, 1);
header.buff_size = 1;
body.buff = calloc(1, 1);
body.buff_size = 1;
curl_handle = setup_curl_options(login_passwd, write_data_in_mem,
(void*)&header, (void*)&body,
server_url);
if (!curl_handle) {
PRINT("failed to initialize curl obj");
free(header.buff);
free(body.buff);
return retval;
}
res = curl_easy_perform(curl_handle);
/* Check for errors */
if (res != CURLE_OK) {
PRINT("curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
retval = -1;
}
} else {
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &resp_code);
retval = 0 ;
}
free(header.buff);
free(body.buff);
if (curl_handle) { /* cleanup */
curl_easy_cleanup(curl_handle);
}
return retval;
}
thread_main(void)
{
int retval = -1;
while(1)
{
retval = contact_server("server1", "pwd", "https://abcd.net")
if(retval == -1)
{
sleep(10);
}
else {
break;
}
}
}Core Analysis
(gdb) info threads
Id Target Id Frame
4 process 100149 0x4863e1e7 in sigwait () at sigwait.S:2
3 process 100127 0x4869a57b in accept () at accept.S:2
2 process 100128 0x486a6a73 in nanosleep () at nanosleep.S:2>>>>>>>>Uses curl
* 1 process 100087 0xfffff078 in ?? ()>>>>>>>>>>>This one is supposed to be waiting on events which are not triggered in the current scenario
(gdb) bt
#0 0xfffff078 in ?? ()
#1 0x4868ad82 in res_queryN (name=0x1 <error: Cannot access memory at address 0x1>, target=<optimized out>)
at bsd/lib/libc/net/getaddrinfo.c:2836
#2 0x48343e5a in dprintf_formatf (data=0xbf9fd1c8, stream=0x4834348e <addbyter>, format=<optimized out>,
ap_save=0x0) at dist/curl/lib/mprintf.c:631
#3 0x482f3e60 in ?? ()
from obj/i386/usr/lib/libcrypto.so.3
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
(gdb) p $sp
$23 = (void *) 0xbf9fc14c
(gdb) t 2
[Switching to thread 2 (process 100128)]
#0 0x486a6a73 in nanosleep () at nanosleep.S:2
2 nanosleep.S: No such file or directory.
(gdb) p/x $sp
$24 = 0xbf9fddfc
(gdb)
$25 = 0xbf9fddfc
(gdb) p 0xbf9fddfc - 0xbf9fc14c
$26 = 7344>>>>>>>>>>>>>>>>>>>>Clearly thread 1 has overwritten beyond it's stack limits
I expected the following
curl/libcurl version
Curl and libcurl 7.54.0
2
3 Public curl releases: 165
4 Command line options: 207
5 curl_easy_setopt() options: 245
6 Public functions in libcurl: 61
7 Contributors: 1538
[curl -V output]
operating system
FreeBSD 6