cURL / Mailing Lists / curl-library / Single Mail


rfc: curl_easy_setopt() typechecker

From: Michal Marek <>
Date: Mon, 25 Feb 2008 15:11:01 +0100


I played a bit with various extensions available in gcc and hacked
together a set of macros that allow for compile-time checking of
parameters passed to curl_easy_setopt(). The result is attached to this
mail as a patch, but needs probably a bit of explanation :) Also, the
patch isn't meant to be checked in as it is now.

How it works:
- curl_easy_setopt() is wrapped into a macro with a fixed number of
  three arguments. Passing less or more results in an error (see below).
- First, __builtin_constant_p() [1] determines, whether the number of
  the option is known at compile time. If it isn't, no checks are done
  and curl_easy_setopt() is called.
- If we know what option the user wants to set, the type of the argument
  is checked with __builtin_types_compatible_p() [1]. If the type
  matches, everything is OK.
- if the type doesn't match, a custom warning is issued using gcc 4.3's
  __attribute__((warning (...))) feature [3]. curl_easy_setopt() is
  called nevertheless

Example (error-checking omitted for sake of brevity):
$ nl -b a test.c
     1 #include <curl/curl.h>
     3 int main()
     4 {
     5 CURL *h = curl_easy_init();
     6 curl_easy_setopt(h, CURLOPT_HTTPPROXYTUNNEL,
     7 curl_easy_setopt(h, CURLOPT_URL, "");
     8 curl_easy_perform(h);
     9 return 0;
    10 }
$ gcc -Wall -O2 -I ./include/ -l curl test.c
test.c: In function ‘main’:
test.c:6: warning: call to ‘_curl_easy_setopt_err_long’ declared with
attribute warning: curl_easy_setopt expects a long argument for this option

Above sounds pretty simple, but of course there are a few gotchas:
- The CURLOPT_SSLENGINE_DEFAULT option doesn't take any argument. This
  means that completely valid code using CURLOPT_SSLENGINE_DEFAULT can
  break due to the three-arg macro. OTOH it shouldn't be too hard to
  pass a dummy option argument. Also, googling for code possibly
  affected by this [3], I only found one project (among open source
  code, that is).
- __builtin_types_compatible_p() only works in C, not C++, so for C++
  there's no typechecking. Although it might be doable using rtti.
- It only works with the not-yet-released gcc 4.3.
- The macros are a bit messy, yeah :). But it's not fatal if the
  typecheck-gcc.h file gets out of sync with curl.h, it just won't check
  newly added options.
- It might not work (read: it might not issue warnings) with -O0
- While it's easy to recognize a char* pointer, checking the various
  function pointers prove rather hard. E.g. it's OK to write
    size_t my_write(void *, size_t, size_t, struct my_buf*);
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write);
  but the typechecker will treat it as a different type than the
  required one :-/

Anyway, except for the issue with CURLOPT_SSLENGINE_DEFAULT, it
shouldn't change API or ABI. I tried a build-test of a bunch of packages
that use libcurl in the openSUSE build service [4] and the only failures
were xmlrpc-c due to CURLOPT_SSLENGINE_DEFAULT and
libopensync-plugin-opie which uses -Werror (it gets what it asks for
;)). I didn't analyze the resulting warnings for false positives yet.
The most common warning is "curl_easy_setopt expects a long argument for
this option" (447 occurences), probably because nobody cares about int
vs. long.

Now the question: are you interested in this? I can offer maintaining
the typecheck-gcc.h file and/or documenting exactly how to maintain it.
Also, it's easy to extend this to cover other libcurl functions
(curl_easy_getinfo() is probably even more interesting than
curl_easy_setopt() due to the pointers involved) if there's interest.


 (requires a registration, but access is otherwise unrestricted)

Received on 2008-02-25