[gnutls-devel] Casting from int to (void *)

Jaak Ristioja jaak.ristioja at cyber.ee
Thu Feb 7 15:10:34 CET 2013


On 07.02.2013 10:34, Nikos Mavrogiannopoulos wrote:
>  What we actually need is for the compiler to be able to do (int->ptr)
> and then (ptr->int) in a way that no information is lost (i.e., the
> last int will be the same as the first).

The compilers try to follow the language standards on these matters and
trying to change the compiler or the language standards is probably not
an option.

According to C99 it is undefined behavior if the value of pointer can't
be represented by the respective integer type. The result of converting
an integer to a pointer and vice versa is implementation-defined. As far
as I know this might mean that converting there and back again might not
be result in the original input, i.e. (x != (int)(void *) x) might hold
for integer x.

> The current approach is, if
> the callbacks are set, then the provided pointer is passed to them,
> and if not, the transport pointer is casted to an integer and provided
> to send(). If there was an issue a function like you describe could be
> used and the the value to a union, but is it really needed? Do you
> think there will be systems where the current behavior will not be
> tolerated? (such a set_berkeley function would solve the warning issue
> though)

The current solution probably works for most x86 setups, but not for
all. The compiler warning is completely reasonable, as it points out
something which might not work properly on some platforms.

I suspect this behavior can't be corrected without breaking the ABI/API.
I think stuff with actual (void *) pointers still works if the
respective callbacks are properly set.

When designing a new API one has to consider that we currently have at
least three different types of situations:

  1) Berkeley socket descriptor and standard recv/send/select.. as
pull/push/pull_timeout functions

  2) Custom transport pointer (void *) and custom pull/push/pull_timeout

  3) Two custom transport pointers (void *) and custom
pull/push/pull_timeout functions

I guess one of the simplest solutions would be to define only one new
function like the following:

  int gnutls_set_transport_berkeley(gnutls_session_t session, int sd);

Something like this would prevent unportable int<->ptr conversions (or
only warnings for users compiling against your library, if you decide to
use such conversions inside GnuTLS anyway). Inside the library you can
either have separate transport objects for "Berkeley" and "Custom", or
an union of some kind or whatever.

For other custom transports, gnutls_transport_set_ptr and
gnutls_transport_set_ptr2 can still be used.

Of course the semantics for the callback functions also need to be
changed. Namely that the callback functions should only be called when a
custom transport is set. If a berkeley transport is set with
gnutls_set_transport_berkeley, then the callbacks (which take a
gnutls_transport_ptr_t a.k.a void * argument) are not called.

This is my proposal.

Best regards,

More information about the Gnutls-devel mailing list