XDR Library and Short Enums

Andrey Simonenko simon at comsys.ntu-kpi.kiev.ua
Tue Apr 24 09:37:12 UTC 2012


On Mon, Apr 16, 2012 at 02:28:50PM +0200, Sebastian Huber wrote:
> Hi,
> 
> the XDR library implementation of xdr_enum() is currently:
> 
> /*
>   * XDR enumerations
>   */
> bool_t
> xdr_enum(XDR *xdrs, enum_t *ep)
> {
> 	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
> 
> 	/*
> 	 * enums are treated as ints
> 	 */
> 	/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
> 		return (xdr_long(xdrs, (long *)(void *)ep));
> 	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
> 		return (xdr_int(xdrs, (int *)(void *)ep));
> 	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
> 		return (xdr_short(xdrs, (short *)(void *)ep));
> 	} else {
> 		return (FALSE);
> 	}
> }
> 
> The enum_t is defined as:
> 
> typedef int32_t enum_t;
> 
> This is problematic with short enums (variable sized enums).  I case of short 
> enums sizeof (enum sizecheck) would be 1.  The ARM EABI lets you a choice 
> between two alternatives described in the document issued by ARM.  See also 
> section 7.1.3 "Enumerated Types"
> 
> http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
> 
> How would you implement and use the XDR library with short enums?  The 
> xdr_enum() can be easily changed to:
> 
> /*
>   * XDR enumerations
>   */
> bool_t
> xdr_enum(XDR *xdrs, enum_t *ep)
> {
> 	/*
> 	 * enums are treated as ints
> 	 */
> 	/* LINTED */ if (sizeof (enum_t) == sizeof (long)) {
> 		return (xdr_long(xdrs, (long *)(void *)ep));
> 	} else /* LINTED */ if (sizeof (enum_t) == sizeof (int)) {
> 		return (xdr_int(xdrs, (int *)(void *)ep));
> 	} else /* LINTED */ if (sizeof (enum_t) == sizeof (short)) {
> 		return (xdr_short(xdrs, (short *)(void *)ep));
> 	} else {
> 		return (FALSE);
> 	}
> }
> 
> The problem is in the XDR library usage.  An example is this (rpc_msg.h):
> 
> enum msg_type {
> 	CALL=0,
> 	REPLY=1
> };
> 
> How would you fix this?  What about
> 
> enum msg_type {
> 	CALL=0,
> 	REPLY=1,
>          _MSG_TYPE_INVALID = 0xffffffff
> };
> 

RFC1832 and RFC4506 specify enumerations:

   Enumerations have the same representation as signed integers.
   Enumerations are handy for describing subsets of the integers.

and specify signed integers:

   An XDR signed integer is a 32-bit datum that encodes an integer in
   the range [-2147483648,2147483647].

Can somebody explain why xdr_enum() implementation has such logic
that does not correspond to the description of XDR enumeration type
in the above mentioned RFCs?

Another question.  xdr_long() translates C 'long' integers to their
external representation.  Actually it converts C 'long' integer to
uint32_t, obviously such conversion is incorrect.

Is is expected that the given value of 'long' type in xdr_long() will
fit to uint32_t type and is not negative?

Example:
-------------------------------------------------------------------
#include <err.h>
#include <stdio.h>

#include <rpc/types.h>
#include <rpc/xdr.h>

#define BUF_SIZE 1024

int
main(void)
{
	char buf[BUF_SIZE] = {};
	XDR xdrs1, xdrs2;
	long x1, x2, y1, y2;

	xdrmem_create(&xdrs1, buf, sizeof(buf), XDR_ENCODE);
	xdrmem_create(&xdrs2, buf, sizeof(buf), XDR_DECODE);

	x1 = 0x0123456789abcdefL;
	x2 = -1;
	if (xdr_long(&xdrs1, &x1) == FALSE || xdr_long(&xdrs1, &x2) == FALSE)
		err(1, "xdr_long(xdrs1)");

	if (xdr_long(&xdrs2, &y1) == FALSE || xdr_long(&xdrs2, &y2) == FALSE)
		err(1, "xdr_long(xdrs2)");

	printf("x1 = 0x%016lx\ny1 = 0x%016lx\n", x1, y1);
	printf("x2 = %ld\ny2 = %ld\n", x2, y2);

	return (0);
}
-------------------------------------------------------------------

Running it on amd64:

x1 = 0x0123456789abcdef
y1 = 0x0000000089abcdef
x2 = -1
y2 = 4294967295


More information about the freebsd-hackers mailing list