curl_easy_perform()在Ubuntu Server 14上崩溃
curl_easy_perform() crashing on Ubuntu Server 14
这是我的上传函数
目标是:根据偏移量和块大小只上传文件的一个块在这个函数中,如果p_offset
不为零,我自己调用fseek()
,然后让libcurl使用fread()
读取文件的内容。
函数的调用者负责给出正确有效的块大小,确保p_offset + p_sizeOfChunk <= ACTUAL_SIZE_OF_FILE
来自服务器的答案应该是一个字符串。我通过回调writeToString()
代码在Windows和OS x上运行良好,但curl_easy_perform()
在Ubuntu 14上有时会崩溃
我的代码中是否缺少任何可能导致此崩溃的内容?
void uploadFile( const string & p_filename, const string & p_url, size_t p_offset, size_t p_sizeOfChunk )
{
FILE * file( fopen( p_filename.c_str(), "rb" ) );
if ( !file )
{
throw Exception( __FILE__, __LINE__ ) << "Could not open file " << p_filename << " when posting to " << p_url;
}
if ( p_offset )
{
if ( fseek( file, (long)p_offset, SEEK_SET ) )
{
throw Exception( __FILE__, __LINE__ ) << "Could not seek in file " << p_filename << " when posting to " << p_url;
}
}
CURL * curl( curl_easy_init() );
if ( !curl )
{
throw Exception( __FILE__, __LINE__ ) << "Could not initialize cURL when posting " << p_filename << " to " << p_url;
}
// URL
curl_easy_setopt( curl, CURLOPT_URL, p_url.c_str() );
// PUT HTTP method
string answer;
curl_easy_setopt( curl, CURLOPT_UPLOAD, 1L );
curl_easy_setopt( curl, CURLOPT_READFUNCTION, fread );
curl_easy_setopt( curl, CURLOPT_READDATA, file );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeToString );
curl_easy_setopt( curl, CURLOPT_WRITEDATA, &answer );
curl_easy_setopt( curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)p_sizeOfChunk );
char errorBuffer[ CURL_ERROR_SIZE + 1 ];
curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, errorBuffer );
// No signal handlers...
curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 );
curl_easy_setopt( curl, CURLOPT_TIMEOUT_MS, 120000 );
// HEADER
char contentLength[ 512 ];
snprintf( contentLength, sizeof( contentLength ), "Content-Length: %zu", p_sizeOfChunk );
struct curl_slist * headers( nullptr );
headers = curl_slist_append( headers, contentLength );
curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers );
// SSL
curl_easy_setopt( curl, CURLOPT_CAINFO, "path/to/cacert.pem" );
CURLcode res( curl_easy_perform( curl ) );
fclose( file );
if ( res != CURLE_OK && res != CURLE_SEND_ERROR )
{
curl_easy_cleanup( curl );
throw Exception( __FILE__, __LINE__ ) << "cURL error when posting " << p_filename << " to " << p_url << ": " << errorBuffer;
}
long httpResponseCode( 0 );
curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &httpResponseCode );
curl_easy_cleanup( curl );
if ( ( httpResponseCode / 100 ) != 2 )
{
cout << answer << endl;
throw Exception( __FILE__, __LINE__ ) << "HTTP error " << httpResponseCode << " when posting " << p_filename;
}
}
我得到答案并记录在std::string
和writeToString()
上。这肯定不是坠机的原因。我测试了它只是返回size * count
和崩溃仍然发生。
static size_t writeToString( const void * ptr, size_t size, size_t count, FILE * stream )
{
string & retContent( *( reinterpret_cast< string * >( stream ) ) );
if ( !retContent.length() )
{
int skipBOM( ( reinterpret_cast< const unsigned char * >( ptr )[ 0 ] == 0xEF && reinterpret_cast< const unsigned char * >( ptr )[ 1 ] == 0xBB && reinterpret_cast< const unsigned char * >( ptr )[ 2 ] == 0xBF ) ? 3 : 0 );
retContent += string( static_cast< const char * >( ptr ) + skipBOM, static_cast< int >( size * count ) - skipBOM );
}
else
{
retContent += string( static_cast< const char * >( ptr ), size * count );
}
return size * count;
}
这是崩溃时的堆栈!它似乎与OpenSSL有关。
#0 0x00007ffff65ad35d in write () at ../sysdeps/unix/syscall-template.S:81
#1 0x00007ffff73187a6 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#2 0x00007ffff731684b in BIO_write () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#3 0x00007ffff6ffcb72 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#4 0x00007ffff6ffd273 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#5 0x00007ffff76873e1 in ossl_send (conn=0x7ffef8013b28, sockindex=0, mem=0x7ffef8005379, len=16384, curlcode=0x7fff127fa5c0) at vtls/openssl.c:2720
#6 0x00007ffff762fe0f in Curl_write (conn=0x7ffef8013b28, sockfd=64, mem=0x7ffef8005379, len=16384, written=0x7fff127fa608) at sendf.c:233
#7 0x00007ffff764fb01 in readwrite_upload (data=0x7ffef8000a78, conn=0x7ffef8013b28, k=0x7ffef8000af0, didwhat=0x7fff127fa664) at transfer.c:954
#8 0x00007ffff764fdd9 in Curl_readwrite (conn=0x7ffef8013b28, done=0x7fff127fa6dc) at transfer.c:1059
#9 0x00007ffff765ced7 in multi_runsingle (multi=0x7ffef800a668, now=..., data=0x7ffef8000a78) at multi.c:1484
#10 0x00007ffff765d60c in curl_multi_perform (multi_handle=0x7ffef800a668, running_handles=0x7fff127fa870) at multi.c:1759
#11 0x00007ffff7652103 in easy_transfer (multi=0x7ffef800a668) at easy.c:705
#12 0x00007ffff7652311 in easy_perform (data=0x7ffef8000a78, events=false) at easy.c:793
#13 0x00007ffff7652364 in curl_easy_perform (easy=0x7ffef8000a78) at easy.c:812
#14 ...
首先…用调试器运行它(或获得适当的核心转储),找出真正失败的地方。
不确定这是否可能是问题…但是查看文档,您在CURLOPT_WRITEFUNCTION
中传递的函数必须具有以下签名:
size_t function( char *ptr, size_t size, size_t nmemb, void *userdata);
但是在你的情况下:
size_t writeToString(const void * ptr, size_t size, size_t count, FILE * stream);
显然CURLOPT_WRITEFUNCTION的默认实现期望一个FILE *在那里…但是在void * form
问题出在一个细节上,我完全误解了。
curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 );
CURLOPT_NOSIGNAL
的效果阻止 libcurl处理任何信号!我最初的解释完全相反。这个错误的发生是因为在OS X上它是工作的[并且管道处理也存在],所以我假设"信号管理"是正确的。我不知道为什么在OS X上没有出现同样的错误。不管怎样,我删除了这一行,它工作得很好。
当然,另一种可能的解决方案是显式地将ir设为0:
curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 0 );
- 当回溯以零开始时,如何调试崩溃
- 内联映射初始化的动态atexit析构函数崩溃
- 执行函数时导致崩溃的变量
- 程序崩溃并显示"std::out_of_range"错误
- CoInitialize()在单独的线程上崩溃而不返回
- 使用调试/崩溃报告将应用程序部署到客户端
- 为什么所有C++编译器都会崩溃或挂起此代码
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 为什么我的多线程作业队列崩溃
- ExtractIconEx:可以工作,但偶尔会崩溃
- 为什么引用传递会导致此崩溃(C++)
- 试图创建流或fopen时程序崩溃
- 类对象数组的问题会导致崩溃
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 为什么要增加导致崩溃的指针
- 在虚幻引擎中删除NXOpen对象时崩溃
- 为什么它只打印双链接列表的第一个值,而我的程序却崩溃了
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- Windows Server 2008 R2上的常见对话框:GetOpenFileName崩溃
- curl_easy_perform()在Ubuntu Server 14上崩溃