3
我用C进行JSON-RPC请求和libcurl中成功地使用以下代码的libcurl:上curl_easy_perform分段故障时WriteMemoryCallback使用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
void post_rpc(CURL *curl_handle)
{
CURLcode res;
char JSONRPC_BASE_URL[] = "https://api.betfair.com/exchange/betting/json-rpc/v1";
char rpc_request[]="{\"jsonrpc\": \"2.0\", \"method\": \"SportsAPING/v1.0/listEventTypes\", \"params\": {\"filter\":{ }}, \"id\": 1}";
char session_token[]= "MY_ACTIVE_SESSION_STRING";
char session_header[100+sizeof(session_token)];
strcpy(session_header, "X-Authentication:");
strcat(session_header, session_token);
struct curl_slist * headers = NULL;
headers = curl_slist_append(headers, "X-Application: MY_API_KEY");
headers = curl_slist_append(headers, session_header);
headers = curl_slist_append(headers, "content-type : application/json");
/* init the curl session */
curl_handle = curl_easy_init();
/* HEADERS */
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
/* POST FIELD : Json-rpc request */
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, rpc_request);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, (long)strlen(rpc_request));
/* stdout the header sent */
curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, stdout);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout);
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, JSONRPC_BASE_URL);
/* get it! */
res = curl_easy_perform(curl_handle);
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
}
int main(){
int res;
CURL *curl_handle;
curl_global_init(CURL_GLOBAL_DEFAULT);
post_rpc(curl_handle);
curl_global_cleanup();
return 0;
}
然而,当我尝试整合getinmemory.c的libcurl示例(在为了获得在一个变量而不是标准输出)的输出,从而上来用下面的代码(其中我已经缩进我的编辑,这基本上是添加上述代码)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
CURL *curl_handle;
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
char JSONRPC_BASE_URL[] = "https://api.betfair.com/exchange/betting/json-rpc/v1";
char rpc_request[]="{\"jsonrpc\": \"2.0\", \"method\": \"SportsAPING/v1.0/listEventTypes\", \"params\": {\"filter\":{ }}, \"id\": 1}";
char session_token[]= "MY_ACTIVE_SESSION_STRING";
char session_header[100+sizeof(session_token)];
strcpy(session_header, "X-Authentication:");
strcat(session_header, session_token);
struct curl_slist * headers = NULL;
headers = curl_slist_append(headers, "X-Application: MY_API_KEY");
headers = curl_slist_append(headers, session_header);
headers = curl_slist_append(headers, "content-type : application/json");
/* HEADERS */
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
/* POST FIELD : Json-rpc request */
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, rpc_request);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, (long)strlen(rpc_request));
/* stdout the header sent */
curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, stdout);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout);
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, JSONRPC_BASE_URL);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
printf("THIS IS PRINTED\n");
fflush(stdout);
/* get it! */
res = curl_easy_perform(curl_handle); //LINE 114: SEGFAULT
printf("THIS IS NOT...\n");
fflush(stdout);
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else {
/*
* Now, our chunk.memory points to a memory block that is chunk.size
* bytes big and contains the remote file.
*
* Do something nice with it!
*/
printf("%lu bytes retrieved\n", (long)chunk.size);
printf("Chunk:%s\n", chunk.memory);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
if(chunk.memory)
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return 0;
}
我得到
res = curl_easy_perform(curl_handle);
分割故障恰好在里面writeMemoryCallback
realloc
电话。
此外,我应该提到,上面的示例中打印在标准输出上的标题不会打印在这里。该集团的印刷版的唯一事情是
$ ./dafuq
THIS IS PRINTED
Segmentation fault
这是gdb的转储
(gdb) break 114
Breakpoint 1 at 0x40116d: file getinmemory.c, line 114.
(gdb) break 115
Breakpoint 2 at 0x40117c: file getinmemory.c, line 115.
(gdb) run
Starting program: dafuq
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
THIS IS PRINTED
Breakpoint 1, main() at getinmemory.c:114
114 res = curl_easy_perform(curl_handle);
(gdb) step
[New Thread 0x7ffff341e700 (LWP 6774)]
[Thread 0x7ffff341e700 (LWP 6774) exited]
Program received signal SIGSEGV, Segmentation fault.
__GI___libc_realloc (oldmem=0xfbad2a84, bytes=140737354092562) at malloc.c:2977
2977 malloc.c: No such file or directory.
(gdb)
的Valgrind的转储:
$ valgrind ./dafuq --tool memcheck
==7002== Memcheck, a memory error detector
==7002== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7002== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==7002== Command: ./dafuq --tool memcheck
==7002==
THIS IS PRINTED
==7002== Invalid free()/delete/delete[]/realloc()
==7002== at 0x4C2AF2E: realloc (vg_replace_malloc.c:692)
==7002== by 0x400D27: WriteMemoryCallback (getinmemory.c:44)
==7002== by 0x4E4BD89: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x4E4A353: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x4E605AF: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x4E6ACE8: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x4E6B560: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x4E6215A: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0)
==7002== by 0x401178: main (getinmemory.c:114)
==7002== Address 0xfbad2a84 is not stack'd, malloc'd or (recently) free'd
==7002==
not enough memory (realloc returned NULL)
THIS IS NOT...
curl_easy_perform() failed: Failed writing received data to disk/application
==7002==
==7002== HEAP SUMMARY:
==7002== in use at exit: 238 bytes in 8 blocks
==7002== total heap usage: 7,171 allocs, 7,163 frees, 67,842,654 bytes allocated
==7002==
==7002== LEAK SUMMARY:
==7002== definitely lost: 16 bytes in 1 blocks
==7002== indirectly lost: 158 bytes in 5 blocks
==7002== possibly lost: 0 bytes in 0 blocks
==7002== still reachable: 64 bytes in 2 blocks
==7002== suppressed: 0 bytes in 0 blocks
==7002== Rerun with --leak-check=full to see details of leaked memory
==7002==
==7002== For counts of detected and suppressed errors, rerun with: -v
==7002== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
有什么想法?
PS:我也尝试使用像来自here的sth代码流,提出了完全相同的行为。
首先检查返回* every *函数的值,然后尝试更换malloc/realloc调用。 – 2501 2014-10-28 14:23:45
http://curl.haxx.se/libcurl/c/postinmemory.html示例可能更接近你想要的... – 2014-10-28 14:47:46
好点。所有的libcurl函数返回0 用''malloc''替换''realloc''给出(在gdb): 编程接收到的信号SIGSEGV,分段错误。 __memcpy_sse2_unaligned() 在../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:35 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:没有这样的文件或目录。 – chefarov 2014-10-28 14:51:32