From 2c66b6d72cd48d3cf80f957f55cfb1548feb46c4 Mon Sep 17 00:00:00 2001
From: Roman Bogorodskiy <bogorodskiy@gmail.com>
Date: Sat, 31 Jan 2026 10:19:35 +0100
Subject: [PATCH] build: add detection of xdrproc_t arguments count

According to 9fa3a8ab6fd82ad2f5a14b490696085061418718,
macOS insists on passing 3 arguments for xdrproc_t.

Passing 3 arguments was a good common ground, but since
recently[1] FreeBSD only accepts 2 arguments.

Add a meson.build check whether 3 arguments are accepted,
and add macros which passes either 2 or 3 arguments to
xdrproc_t based on the result of this check.

1: https://cgit.freebsd.org/src/commit/?id=ac5a19ec6989675c8ec6c3ca245dba243d1a6416

Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
---
 meson.build                      | 19 +++++++++++++++++++
 scripts/rpcgen/tests/test_demo.c | 12 +++++++++---
 src/rpc/virnetmessage.c          | 10 ++++++++--
 3 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/meson.build b/meson.build
index a6db70f13e..b30e9136a2 100644
--- a/meson.build
+++ b/meson.build
@@ -894,6 +894,25 @@ else
   xdr_dep = dependency('', required: false)
 endif
 
+if xdr_dep.found()
+  xdrproc_3arg_code = '''
+  #include <rpc/xdr.h>
+
+  bool_t test_filter(XDR *xdr, void *data, unsigned int opaque_flags) {
+      return TRUE;
+  }
+
+  int main() {
+      XDR xdr;
+      xdrproc_t filter = (xdrproc_t)&test_filter;
+      (*filter)(&xdr, NULL, 0);
+      return 0;
+  }
+  '''
+  if cc.compiles(xdrproc_3arg_code, dependencies: xdr_dep)
+    conf.set('XDRPROC_T_3ARGS', 1)
+  endif
+endif
 
 # generic build dependencies
 
diff --git a/scripts/rpcgen/tests/test_demo.c b/scripts/rpcgen/tests/test_demo.c
index e6ba7ddbc5..82eda89592 100644
--- a/scripts/rpcgen/tests/test_demo.c
+++ b/scripts/rpcgen/tests/test_demo.c
@@ -8,6 +8,12 @@
 # define xdr_uint64_t xdr_u_int64_t
 #endif
 
+#if defined(XDRPROC_T_3ARGS)
+# define XDRPROC(proc, xdr, data) (proc(&xdr, data, 0))
+#else
+# define XDRPROC(proc, xdr, data) (proc(&xdr, data))
+#endif
+
 #include "demo.h"
 #include "demo.c"
 
@@ -27,7 +33,7 @@ static void test_xdr(xdrproc_t proc, void *vorig, void *vnew, const char *testna
     /* Step 1:  serialize the vorig and compare to the data in test .bin files */
     xdrmem_create(&xdr, buf, buflen, XDR_ENCODE);
 
-    ret = !!proc(&xdr, vorig, 0);
+    ret = !!XDRPROC(proc, xdr, vorig);
     g_assert_cmpint(ret, ==, !fail);
 
     if (fail)
@@ -54,7 +60,7 @@ static void test_xdr(xdrproc_t proc, void *vorig, void *vnew, const char *testna
     /* Step 2: de-serialize the state to create a new object */
     xdrmem_create(&xdr, buf, buflen, XDR_DECODE);
 
-    ret = !!proc(&xdr, vnew, 0);
+    ret = !!XDRPROC(proc, xdr, vnew);
     g_assert_cmpint(ret, ==, true);
 
     actlen = xdr_getpos(&xdr);
@@ -68,7 +74,7 @@ static void test_xdr(xdrproc_t proc, void *vorig, void *vnew, const char *testna
 
     xdrmem_create(&xdr, buf, buflen, XDR_ENCODE);
 
-    ret = !!proc(&xdr, vnew, 0);
+    ret = !!XDRPROC(proc, xdr, vnew);
     g_assert_cmpint(ret, ==, true);
 
     actlen = xdr_getpos(&xdr);
diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c
index af0f9cb30b..e66df5c9e2 100644
--- a/src/rpc/virnetmessage.c
+++ b/src/rpc/virnetmessage.c
@@ -34,6 +34,12 @@
 
 VIR_LOG_INIT("rpc.netmessage");
 
+#if defined(XDRPROC_T_3ARGS)
+# define XDRPROC_FILTER(filter, xdr, data) ((*filter)(&xdr, data, 0))
+#else
+# define XDRPROC_FILTER(filter, xdr, data) ((*filter)(&xdr, data))
+#endif
+
 virNetMessage *virNetMessageNew(bool tracked)
 {
     virNetMessage *msg;
@@ -367,7 +373,7 @@ int virNetMessageEncodePayload(virNetMessage *msg,
                   msg->bufferLength - msg->bufferOffset, XDR_ENCODE);
 
     /* Try to encode the payload. If the buffer is too small increase it. */
-    while (!(*filter)(&xdr, data, 0)) {
+    while (!XDRPROC_FILTER(*filter, xdr, data)) {
         unsigned int newlen = msg->bufferLength - VIR_NET_MESSAGE_LEN_MAX;
         newlen *= 2;
 
@@ -424,7 +430,7 @@ int virNetMessageDecodePayload(virNetMessage *msg,
     xdrmem_create(&xdr, msg->buffer + msg->bufferOffset,
                   msg->bufferLength - msg->bufferOffset, XDR_DECODE);
 
-    if (!(*filter)(&xdr, data, 0)) {
+    if (!XDRPROC_FILTER(*filter, xdr, data)) {
         virReportError(VIR_ERR_RPC, "%s", _("Unable to decode message payload"));
         goto error;
     }
-- 
GitLab

