FFI Program not working on Mac

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;
}
3 Likes