Here is the fix!
The third argument of curl_easy_setopt
is variadic (those ...
in C), so this needs to be reflected in the type signature in order for the calling convention to work.
(define-curl curl_easy_setopt_url
(_fun #:varargs-after 2
(h val) ::
(h : _curl) (_uint = 10002) (val : _string) -> _int)
#:c-id curl_easy_setopt)
(define-curl curl_easy_setopt_verbose
(_fun #:varargs-after 2
(h val) ::
(h : _curl) (_uint = 41) (val : _long) -> _int)
#:c-id curl_easy_setopt)
This difference is sort of more evident when I tried to translate this into C. If you change the type of the third argument of dyn_curl_easy_setopt_url
to char*
, the C program ends up crashing.
#include <stdio.h>
#include <dlfcn.h>
#include <curl/curl.h>
CURLcode (*dyn_curl_global_init)(long flags);
void (*dyn_curl_global_cleanup)(void);
CURL* (*dyn_curl_easy_init)(void);
CURLcode (*dyn_curl_easy_setopt_verbose)(CURL *handle, unsigned int, ...);
CURLcode (*dyn_curl_easy_setopt_url)(CURL *handle, unsigned int, ...);
// ^HERE
CURLcode (*dyn_curl_easy_perform)(CURL *easy_handle);
void (*dyn_curl_easy_cleanup)(CURL *handle);
int main(void) {
void* hcurl = dlopen("libcurl.dylib", RTLD_NOW);
dyn_curl_global_init = dlsym(hcurl, "curl_global_init");
dyn_curl_global_cleanup = dlsym(hcurl, "curl_global_cleanup");
dyn_curl_easy_init = dlsym(hcurl, "curl_easy_init");
dyn_curl_easy_setopt_verbose = dlsym(hcurl, "curl_easy_setopt");
dyn_curl_easy_setopt_url = dlsym(hcurl, "curl_easy_setopt");
dyn_curl_easy_perform = dlsym(hcurl, "curl_easy_perform");
dyn_curl_easy_cleanup = dlsym(hcurl, "curl_easy_cleanup");
dyn_curl_global_init(CURL_GLOBAL_ALL);
CURL *curl = dyn_curl_easy_init();
if(curl) {
CURLcode res = 0;
dyn_curl_easy_setopt_verbose(curl, CURLOPT_VERBOSE, 1L);
dyn_curl_easy_setopt_url(curl, CURLOPT_URL, "https://www.google.com");
res = dyn_curl_easy_perform(curl);
dyn_curl_easy_cleanup(curl);
}
dyn_curl_global_cleanup();
dlclose(hcurl);
return 0;
}