The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=ac5a19ec6989675c8ec6c3ca245dba243d1a6416
commit ac5a19ec6989675c8ec6c3ca245dba243d1a6416 Author: Brooks Davis <[email protected]> AuthorDate: 2026-01-23 10:35:32 +0000 Commit: Brooks Davis <[email protected]> CommitDate: 2026-01-23 10:35:32 +0000 rpc/xdr.h: make xdrproc_t always take two arguments The type of xdrproc_t is clearly defined in the comments as a function with two arguments, an XDR * and a void * (sometimes spelled caddr_t). It was initialy defined as: typedef bool_t (*xdrproc_t)(); At some point people started giving it a non-empty argument list. Unfortunatly, there has been widespread disagreement about how arguments are passed. There seems to have been a widespread view that it should be allowed to pass three argument function pointer to xdrproc_t. Most notable is xdr_string which takes a maximum length parameter. This lead to all sorts of prototypes (all of which have been present in the FreeBSD source tree): FreeBSD userspace (nominally from tirpc, but seemingly local): typedef bool_t (*xdrproc_t)(XDR *, ...); FreeBSD kernel, glibc: typedef bool_t (*xdrproc_t)(XDR *, void *, ...); rcp/xdr.h with _KERNEL defined (not used?): typedef bool_t (*xdrproc_t)(XDR *, void *, u_int); gssrpc (in krb5) and Linux kernel: typedef bool_t (*xdrproc_t)(XDR *, void *); For two argument functions on current ABIs, these all equivalent as these arguments are passed in registers regardless of decleration and definition, but we end up with two problems: - xdr_free((xdrproc_t)xdr_string, ...) calls xdr_string with no third argument and (at least on FreeBSD) may fail to free memory if the string is shorter than the value lying around in the third argument register. There are no instance of this in tree, but I found some with Debian code search, in particular in OpenAFS. - Under CheriABI, variadic arguments are passed in a separate, bounded array so theses prototypes aren't equilvalent to the non-variadic calling convention of the functions. The reality is that that xdr_string should not be cast to xdrproc_t and xdr_wrapstring should be used instead so we do not need to support this case. Instances of the former behavior are now extremely rare. With this change we bring FreeBSD in line with gssrpc and the Linux Kernel. Warnings about casts should now be correct and should be fixed. Bump __FreeBSD_version as some software required adaptation if it is declaring functions to cast to xdrproc_t. Update OpenZFS's workaround of this historic mess accordingly. Effort: CHERI upstreaming Sponsored by: Innovate UK Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D54824 --- include/rpc/xdr.h | 9 +-------- lib/libc/rpc/rpc.3 | 4 ++-- sys/contrib/openzfs/module/nvpair/nvpair.c | 3 ++- sys/rpc/xdr.h | 9 +-------- sys/sys/param.h | 2 +- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/include/rpc/xdr.h b/include/rpc/xdr.h index ecf10e1659e4..4c75bcc5bbf7 100644 --- a/include/rpc/xdr.h +++ b/include/rpc/xdr.h @@ -129,14 +129,7 @@ typedef struct XDR { * to be decoded. If this pointer is 0, then the type routines should * allocate dynamic storage of the appropriate size and return it. */ -#ifdef _KERNEL -typedef bool_t (*xdrproc_t)(XDR *, void *, u_int); -#else -/* - * XXX can't actually prototype it, because some take three args!!! - */ -typedef bool_t (*xdrproc_t)(XDR *, ...); -#endif +typedef bool_t (*xdrproc_t)(XDR *, void *); /* * Operations defined on a XDR handle diff --git a/lib/libc/rpc/rpc.3 b/lib/libc/rpc/rpc.3 index 12d19df117ad..7ae3ec5c5aeb 100644 --- a/lib/libc/rpc/rpc.3 +++ b/lib/libc/rpc/rpc.3 @@ -254,9 +254,9 @@ enum xdr_op { * structure of the data type to be decoded. If this points to 0, * then the type routines should allocate dynamic storage of the * appropriate size and return it. - * bool_t (*xdrproc_t)(XDR *, caddr_t *); + * bool_t (*xdrproc_t)(XDR *, void *); */ -typedef bool_t (*xdrproc_t)(); +typedef bool_t (*xdrproc_t)(XDR *, void *); /* * The XDR handle. diff --git a/sys/contrib/openzfs/module/nvpair/nvpair.c b/sys/contrib/openzfs/module/nvpair/nvpair.c index eb8c14b4a783..cb3a024ec95c 100644 --- a/sys/contrib/openzfs/module/nvpair/nvpair.c +++ b/sys/contrib/openzfs/module/nvpair/nvpair.c @@ -3246,7 +3246,8 @@ nvs_xdr_nvl_fini(nvstream_t *nvs) * xdrproc_t-compatible callbacks for xdr_array() */ -#if defined(_KERNEL) && defined(__linux__) /* Linux kernel */ +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 1600010) || \ + defined(_KERNEL) && defined(__linux__) /* Linux kernel */ #define NVS_BUILD_XDRPROC_T(type) \ static bool_t \ diff --git a/sys/rpc/xdr.h b/sys/rpc/xdr.h index 4307b5101477..b3eafcb864b2 100644 --- a/sys/rpc/xdr.h +++ b/sys/rpc/xdr.h @@ -133,14 +133,7 @@ typedef struct XDR { * to be decoded. If this pointer is 0, then the type routines should * allocate dynamic storage of the appropriate size and return it. */ -#ifdef _KERNEL -typedef bool_t (*xdrproc_t)(XDR *, void *, ...); -#else -/* - * XXX can't actually prototype it, because some take three args!!! - */ -typedef bool_t (*xdrproc_t)(XDR *, ...); -#endif +typedef bool_t (*xdrproc_t)(XDR *, void *); /* * Operations defined on a XDR handle diff --git a/sys/sys/param.h b/sys/sys/param.h index a5dd31519ea5..410d18b53df6 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -74,7 +74,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1600009 +#define __FreeBSD_version 1600010 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
