use*_*108 5 c c++ lambda c++11
如果我实现这样的C回调:
register_callback([](/*some args*/){/*some stuff*/});
Run Code Online (Sandbox Code Playgroud)
触发时我得到一个SIGSEGV,但如果我这样注册:
auto const f([](/*some args*/){/*some stuff*/});
register_callback(f);
Run Code Online (Sandbox Code Playgroud)
然后它工作正常.(对我来说)特别感兴趣的是地址消毒剂产生的堆栈跟踪:
ASAN:SIGSEGV
=================================================================
==22904==ERROR: AddressSanitizer: SEGV on unknown address 0x7f1582c54701 (pc 0x7f1582c54701 sp 0x7f1582c544a8 bp 0x7f1582c54510 T2)
#0 0x7f1582c54700 ([stack:22906]+0x7fc700)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0 ??
Run Code Online (Sandbox Code Playgroud)
它看起来好像函数指针指向堆栈.将lambda推入堆栈会将代码压入堆栈吗?由于我没有捕获任何函数指针的位置对我来说是一个谜.怎么了?没有使用优化标志.我不是在寻找解决方法.
编辑:显然'+'是一个工作示例的关键.我不知道为什么有必要.使用compile删除'+'和示例,但将使用clang-3.5和触发SIGSEGV gcc-4.9.
#include <curl/curl.h>
#include <ostream>
#include <iostream>
int main()
{
auto const curl(curl_easy_init());
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "cnn.com");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
/*
auto const f([](char* const ptr, size_t const size, size_t const nmemb,
void* const data)
{
*static_cast<::std::ostream*>(data) << ptr;
return size * nmemb;
}
);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +f);
*/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
+[](char* const ptr, size_t const size, size_t const nmemb,
void* const data)
{
*static_cast<::std::ostream*>(data) << ptr;
return size * nmemb;
}
);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &::std::cout);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
curl_easy_setopt定义为(in curl/easy.h):
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
Run Code Online (Sandbox Code Playgroud)
That means that the third argument param must be of a type that can be passed as a C variadic. Unfortunately, while curl_easy_setopt is expecting a function pointer, passing class objects (and lambdas are class objects) is "conditionally-supported with implementation-defined semantics" ([expr.call]/7), so the compiler accepts it but then curl_easy_setopt tries to interpret the lambda object as a function pointer, with catastrophic results.
The object that you actually pass is a captureless lambda which means that it is an empty class object, of size 1 byte (all most-derived objects must be at least one byte in size). The compiler will promote that argument to a word-size integer (4 bytes on 32-bit, 8 bytes on 64-bit) and either pass 0 or leave that register/stack slot unset, meaning that garbage gets passed (since the lambda doesn't actually use its memory footprint when called).
| 归档时间: |
|
| 查看次数: |
461 次 |
| 最近记录: |