我正在开发一个C++项目,我使用libcurl通过SMTP发送电子邮件.代码几乎适用于小内容,但是,对于较大的电子邮件,它会引发写入访问冲突,我看不出任何原因.
以下是我使用curl函数发送邮件的方式:
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);
Run Code Online (Sandbox Code Playgroud)
下面是read函数回调
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;
}
Run Code Online (Sandbox Code Playgroud)
它this->upload_ctx.lines_read++;在第5次调用后崩溃(向量lineArray和upload_ctx-> lines_read中有6行是5.
完整的错误消息是:
Exception thrown at 0x00007FFF4E8F16D7 (vcruntime140d.dll) in myapp.exe: 0xC0000005: Access violation writing location 0x00000205CC8AC000.
Run Code Online (Sandbox Code Playgroud)
概要
Run Code Online (Sandbox Code Playgroud)#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);描述
将指针传递给回调函数,如上面的原型所示。
当 libcurl 需要读取数据以便将其发送到对等方时,该回调函数就会被调用 - 就像您要求它上传或发布数据到服务器一样。指针缓冲区指向的数据区域最多应填充函数字节数的乘积
sizenitems。
你写了:
size_t len = strlen(data);
memcpy(ptr, data, len);
Run Code Online (Sandbox Code Playgroud)
由于len仅取决于要发送的数据,并且由于您不检查它是否小于size*nitems(nmemb对您而言),因此您可能会从 libcurl 分配的缓冲区中写出,因此调用未定义的行为。
由于您按行工作,而 libcurl 按字节工作,因此您需要重新编写应用程序以跟踪部分写入的行,或者完全放弃行的概念。