From 963ed7507e340fcdab4774531337e6188474a1fb Mon Sep 17 00:00:00 2001 From: "Davide \"FunkyAss\" Del Zompo" Date: Thu, 22 May 2014 20:08:32 +0200 Subject: [PATCH 1/2] callbacks: fix segmentation fault Performing a request defining custom callbacks, then performing another request without callbacks (i.e. using libcurl default callbacks) causes a segmentation fault: -- assume the easy handle is properly set up easy:perform{writefunction = function(chunk) io.write(chunk) end} -- the answer is written to stdout -- easy:perform() -- segmentation fault (in fwrite () from libc) The above segmentation fault happens because the data pointer, set with CURLOPT_WRITEDATA (CURLOPT_FILE) in curl_easy_setopt, for the write function (fwrite for default callbacks) is not properly cleaned up and the lua_State from the previous callback is passed. Similar faults will show up with CURLOPT_WRITEHEADER and CURLOPT_READDATA (CURLOPT_INFILE). In order to properly restore the default callback behaviours: - the "write function" data pointer must be set back to stdout; - the "header function" data pointer must be set to NULL; - the "read function" data pointer must be set to stdin; About the values for data pointers: despite the libcurl documentation says nothing about their default values, reading libcurl source code leads to stdout, stdin and NULL (actually 0x0). Signed-off-by: Davide "FunkyAss" Del Zompo --- src/Lua-cURL-callback.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Lua-cURL-callback.c b/src/Lua-cURL-callback.c index e82b510..6ced8e4 100644 --- a/src/Lua-cURL-callback.c +++ b/src/Lua-cURL-callback.c @@ -22,6 +22,7 @@ ******************************************************************************/ #include /* memcpy */ +#include /* stdin, stdout */ #include "Lua-cURL.h" #include "Lua-utility.h" @@ -95,6 +96,8 @@ int l_easy_clear_headerfunction(lua_State *L, CURL* curl) { l_easy_private *privatep = luaL_checkudata(L, 1, LUACURL_EASYMETATABLE); if (curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, NULL) != CURLE_OK) luaL_error(L, "%s", privatep->error); + if (curl_easy_setopt(curl, CURLOPT_WRITEHEADER, NULL) != CURLE_OK) + luaL_error(L, "%s", privatep->error); return 0; } @@ -102,6 +105,8 @@ int l_easy_clear_writefunction(lua_State *L, CURL* curl) { l_easy_private *privatep = luaL_checkudata(L, 1, LUACURL_EASYMETATABLE); if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL) != CURLE_OK) luaL_error(L, "%s", privatep->error); + if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout) != CURLE_OK) + luaL_error(L, "%s", privatep->error); return 0; } @@ -109,5 +114,7 @@ int l_easy_clear_readfunction(lua_State *L, CURL* curl) { l_easy_private *privatep = luaL_checkudata(L, 1, LUACURL_EASYMETATABLE); if (curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL) != CURLE_OK) luaL_error(L, "%s", privatep->error); + if (curl_easy_setopt(curl, CURLOPT_READDATA, stdin) != CURLE_OK) + luaL_error(L, "%s", privatep->error); return 0; } From f307002585af28234a5517bbd5fb69637c82e90f Mon Sep 17 00:00:00 2001 From: "Davide \"FunkyAss\" Del Zompo" Date: Fri, 23 May 2014 13:51:21 +0200 Subject: [PATCH 2/2] callbacks: fix attempt to call a nil value Performing a request with custom callbacks that returns anything but CURLE_OK, then performing a request with default callbacks causes lua to call a nil value: -- assume the easy handle is properly set up easy:setopt_url("http://mispelled-domain/") -- curl_perform will return CURLE_COULDNT_RESOLVE_HOST pcall(easy.perform, easy, {writefunction = function(chunk) return end} ) -- a totally legit url easy:setopt_url("http://example.com") easy:perform() -- lua: attempt to call a nil value When curl_easy_perform returns anything but CURLE_OK, l_easy_perform calls luaL_error, which ends doing a longjump. The callbacks cleanup never happens, leaving the lua-curl "callback handlers" (l_easy_writefunction, readfuntion, headerfunction) registered. The subsequent request doesn't register any callback, so an empty table is pushed on the stack and the callback handler will call a nil value. Signed-off-by: Davide "FunkyAss" Del Zompo --- src/Lua-cURL.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Lua-cURL.c b/src/Lua-cURL.c index bcb61ba..851d4b0 100644 --- a/src/Lua-cURL.c +++ b/src/Lua-cURL.c @@ -128,6 +128,8 @@ int l_easy_perform(lua_State *L) { int headerfunction; /* do readcallback */ int readfunction; + /* curl_easy_perform return code*/ + CURLcode perform_status; /* check optional callback table */ luaL_opt(L, luaL_checktable, 2, lua_newtable(L)); @@ -155,8 +157,7 @@ int l_easy_perform(lua_State *L) { /* callback table is on top on stack */ - if (curl_easy_perform(curl) != CURLE_OK) - luaL_error(L, "%s", privatep->error); + perform_status = curl_easy_perform(curl); /* unset callback functions */ if (headerfunction) @@ -165,6 +166,10 @@ int l_easy_perform(lua_State *L) { l_easy_clear_writefunction(L, privatep->curl); if (readfunction) l_easy_clear_readfunction(L, privatep->curl); + + if (perform_status != CURLE_OK) + return luaL_error(L, "%s", privatep->error); + return 0; }