I am working on a C++ project where I am using libcurl to send an email over SMTP. The code is pretty much working for small content, however, on larger emails, its throwing a write access violation and I can't see any reason why.
Below is how I am using the curl function to send mail:
curl = curl_easy_init(); //curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); if (curl) { if (this->useVerboseOutput) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); } curl_easy_setopt(curl, CURLOPT_URL, smtpAddress.c_str()); if (this->useTLS) { curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); } if (this->useAuthentication) { if (this->username.empty() || this->password.empty()) { throw logic_error("SMTP username or password has not been set but authentication is enabled"); } curl_easy_setopt(curl, CURLOPT_USERNAME, this->username.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, this->password.c_str()); } curl_easy_setopt(curl, CURLOPT_MAIL_FROM, this->fromAddress.c_str()); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); curl_easy_setopt(curl, CURLOPT_READDATA, this); curl_easy_setopt(curl, CURLOPT_READFUNCTION, &EmailSender::invoke_write_data); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); //Send the message res = curl_easy_perform(curl);
Below is the read function call back
size_t EmailSender::invoke_write_data(void *data, size_t size, size_t nmemb, void* pInstance) { return ((EmailSender*)pInstance)->payload_source(data, size, nmemb); } size_t EmailSender::payload_source(void *ptr, size_t size, size_t nmemb) { //struct upload_status *upload_ctx = (struct upload_status*)userp; const char *data; if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { return 0; } if (this->upload_ctx.lines_read < this->lineArray.size()) { data = this->lineArray.at(this->upload_ctx.lines_read).c_str(); } else { return 0; } if (data) { size_t len = strlen(data); memcpy(ptr, data, len); this->upload_ctx.lines_read++; return len; } return 0; }
Its crashing on the line this->upload_ctx.lines_read++;
after the 5th call (there are 6 lines in the vector lineArray and upload_ctx->lines_read is 5.
The full error message is:
Exception thrown at 0x00007FFF4E8F16D7 (vcruntime140d.dll) in myapp.exe: 0xC0000005: Access violation writing location 0x00000205CC8AC000.
1 Answers
Answers 1
According to the documentation of CURLOPT_READFUNCTION
:
SYNOPSIS
#include <curl/curl.h> size_t read_callback(char *buffer, size_t size, size_t nitems, void *instream); CURLcode curl_easy_setopt(CURL *handle, CURLOPT_READFUNCTION, read_callback);
DESCRIPTION
Pass a pointer to your callback function, as the prototype shows above.
This callback function gets called by libcurl as soon as it needs to read data in order to send it to the peer - like if you ask it to upload or post data to the server. The data area pointed at by the pointer buffer should be filled up with at most
size
multiplied withnitems
number of bytes by your function.
You wrote:
size_t len = strlen(data); memcpy(ptr, data, len);
Since len
only depends on your data to send, and since you do not check it is less than size*nitems
(nmemb
for you), you might write out of the buffer allocated by libcurl, hence invoke undefined behavior.
Since you work by line but libcurl works by byte, you will need to rework your application to keep track of partially written lines, or drop the notion of line altogether.
0 comments:
Post a Comment