[libvirt] [PATCH] Rewrite the way mockable functions are handled.

Daniel P. Berrange posted 1 patch 6 years, 9 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20170712160622.2731-1-berrange@redhat.com
There is a newer version of this series
build-aux/mock-noinline.pl      |  35 ++++++-------
src/internal.h                  |  59 +++++++++++----------
src/qemu/qemu_capabilities.c    |   9 ++--
src/qemu/qemu_capspriv.h        |   2 +-
src/rpc/virnetsocket.c          |  48 ++++++++++-------
src/rpc/virnetsocket.h          |   6 +--
src/util/vircommand.c           |   6 ++-
src/util/vircommand.h           |   2 +-
src/util/vircrypto.c            |   5 +-
src/util/vircrypto.h            |   2 +-
src/util/virfile.c              |   5 +-
src/util/virfile.h              |   2 +-
src/util/virhostcpu.c           |  10 ++--
src/util/virhostcpu.h           |   4 +-
src/util/virmacaddr.c           |   6 ++-
src/util/virmacaddr.h           |   2 +-
src/util/virnetdev.c            |  23 +++++----
src/util/virnetdev.h            |   9 ++--
src/util/virnetdevip.c          |   9 ++--
src/util/virnetdevip.h          |   2 +-
src/util/virnetdevopenvswitch.c |   8 +--
src/util/virnetdevopenvswitch.h |   2 +-
src/util/virnetdevtap.c         |  45 ++++++++--------
src/util/virnetdevtap.h         |   6 +--
src/util/virnuma.c              | 111 +++++++++++++++++++++++-----------------
src/util/virnuma.h              |  16 +++---
src/util/virrandom.c            |  18 ++++---
src/util/virrandom.h            |   6 +--
src/util/virscsi.c              |  13 ++---
src/util/virscsi.h              |   2 +-
src/util/virscsivhost.c         |   5 +-
src/util/virscsivhost.h         |   2 +-
src/util/virtpm.c               |   5 +-
src/util/virtpm.h               |   2 +-
src/util/virutil.c              |  33 +++++++-----
src/util/virutil.h              |  10 ++--
src/util/viruuid.c              |   5 +-
src/util/viruuid.h              |   2 +-
38 files changed, 296 insertions(+), 241 deletions(-)
[libvirt] [PATCH] Rewrite the way mockable functions are handled.
Posted by Daniel P. Berrange 6 years, 9 months ago
Currently any mockable functions are marked with attributes
noinline, noclone and weak. This prevents the compiler from
optimizing away the impl of these functions.

It has an unfortunate side effect with the libtool convenience
libraries, if executables directly link to them. For example
virlockd, virlogd both link to libvirt_util.la  When this is
done, the linker does not consider weak symbols as being
undefined, so it never copies them into the final executable.

In this new approach, we stop annotating the headers entirely.
Instead we create a weak function alias in the source.

   int fooImpl(void) {
      ..the real code..
   }

   int foo(void) __attribute__((noinline, noclone, weak, alias("fooImpl"))

If any functions in the same file call "foo", this prevents the
optimizer from inlining any part of fooImpl. When linking to the
libtool convenience static library, we also get all the symbols
present. Finally the test suite can just directly define a
'foo' function in its source, removing the need to use LD_PRELOAD
(though removal of LD_PRELOADS is left for a future patch).

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 build-aux/mock-noinline.pl      |  35 ++++++-------
 src/internal.h                  |  59 +++++++++++----------
 src/qemu/qemu_capabilities.c    |   9 ++--
 src/qemu/qemu_capspriv.h        |   2 +-
 src/rpc/virnetsocket.c          |  48 ++++++++++-------
 src/rpc/virnetsocket.h          |   6 +--
 src/util/vircommand.c           |   6 ++-
 src/util/vircommand.h           |   2 +-
 src/util/vircrypto.c            |   5 +-
 src/util/vircrypto.h            |   2 +-
 src/util/virfile.c              |   5 +-
 src/util/virfile.h              |   2 +-
 src/util/virhostcpu.c           |  10 ++--
 src/util/virhostcpu.h           |   4 +-
 src/util/virmacaddr.c           |   6 ++-
 src/util/virmacaddr.h           |   2 +-
 src/util/virnetdev.c            |  23 +++++----
 src/util/virnetdev.h            |   9 ++--
 src/util/virnetdevip.c          |   9 ++--
 src/util/virnetdevip.h          |   2 +-
 src/util/virnetdevopenvswitch.c |   8 +--
 src/util/virnetdevopenvswitch.h |   2 +-
 src/util/virnetdevtap.c         |  45 ++++++++--------
 src/util/virnetdevtap.h         |   6 +--
 src/util/virnuma.c              | 111 +++++++++++++++++++++++-----------------
 src/util/virnuma.h              |  16 +++---
 src/util/virrandom.c            |  18 ++++---
 src/util/virrandom.h            |   6 +--
 src/util/virscsi.c              |  13 ++---
 src/util/virscsi.h              |   2 +-
 src/util/virscsivhost.c         |   5 +-
 src/util/virscsivhost.h         |   2 +-
 src/util/virtpm.c               |   5 +-
 src/util/virtpm.h               |   2 +-
 src/util/virutil.c              |  33 +++++++-----
 src/util/virutil.h              |  10 ++--
 src/util/viruuid.c              |   5 +-
 src/util/viruuid.h              |   2 +-
 38 files changed, 296 insertions(+), 241 deletions(-)

diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl
index 2745d4b..1d39300 100644
--- a/build-aux/mock-noinline.pl
+++ b/build-aux/mock-noinline.pl
@@ -1,28 +1,28 @@
 #!/usr/bin/perl
 
-my %noninlined;
+my %mockable;
 my %mocked;
 
 # Functions in public header don't get the noinline annotation
 # so whitelist them here
-$noninlined{"virEventAddTimeout"} = 1;
+$mockable{"virEventAddTimeout"} = 1;
 
 foreach my $arg (@ARGV) {
-    if ($arg =~ /\.h$/) {
-        #print "Scan header $arg\n";
-        &scan_annotations($arg);
-    } elsif ($arg =~ /mock\.c$/) {
+    if ($arg =~ /mock\.c$/) {
         #print "Scan mock $arg\n";
         &scan_overrides($arg);
+    } elsif ($arg =~ /\.c$/) {
+        #print "Scan source $arg\n";
+        &scan_annotations($arg);
     }
 }
 
 my $warned = 0;
 foreach my $func (keys %mocked) {
-    next if exists $noninlined{$func};
+    next if exists $mockable{$func};
 
     $warned++;
-    print STDERR "$func is mocked at $mocked{$func} but missing noinline annotation\n";
+    print STDERR "$func is mocked at $mocked{$func} but missing VIR_MOCKABLE impl\n";
 }
 
 exit $warned ? 1 : 0;
@@ -34,19 +34,16 @@ sub scan_annotations {
     open FH, $file or die "cannot read $file: $!";
 
     my $func;
+    my $mockable = 0;
     while (<FH>) {
-        if (/^\s*(\w+)\(/ || /^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(/) {
-            my $name = $1;
-            if ($name !~ /ATTRIBUTE/) {
-                $func = $name;
-            }
-        } elsif (/^\s*$/) {
-            $func = undef;
-        }
-        if (/ATTRIBUTE_MOCKABLE/) {
-            if (defined $func) {
-                $noninlined{$func} = 1;
+        if (/^VIR_MOCKABLE/) {
+            $mockable = 1;
+        } elsif ($mockable) {
+            if (/^\s*(\w+),$/) {
+                my $func = $1;
+                $mockable{$func} = 1;
             }
+            $mockable = 0;
         }
     }
 
diff --git a/src/internal.h b/src/internal.h
index edc3587..e34338e 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -113,33 +113,6 @@
 # endif
 
 /**
- * ATTRIBUTE_MOCKABLE:
- *
- * Ensure that the symbol can be overridden in a mock
- * library preload. This implies a number of attributes
- *
- *  - noinline: prevents the body being inlined to
- *              callers,
- *  - noclone: prevents specialized copies of the
- *             function body being created for different
- *             callers
- *  - weak: prevents the compiler making optimizations
- *          such as constant return value propagation
- *
- */
-# ifndef ATTRIBUTE_MOCKABLE
-#  if defined(WIN32)
-#   define ATTRIBUTE_MOCKABLE
-#  else
-#   if __GNUC_PREREQ(4, 5)
-#    define ATTRIBUTE_MOCKABLE __attribute__((__noinline__, __noclone__, __weak__))
-#   else
-#    define ATTRIBUTE_MOCKABLE __attribute__((__noinline__, __weak__))
-#   endif
-#  endif
-# endif
-
-/**
  * ATTRIBUTE_FMT_PRINTF
  *
  * Macro used to check printf like functions, if compiling
@@ -251,6 +224,38 @@
 
 
 /*
+ * VIR_MOCKABLE(return type, func name, args...)
+ *
+ * Defines a function implementation that can be later overriden in
+ * the test suite
+ *
+ * NB, Win32 can't use 'weak' attribute because such symbols
+ * can't be marked exported in DLLs
+ *
+ * NB, the ${name}Impl function ought to be static, but that
+ * causes CLang to throw bogus errors about unused functions,
+ * despite there being an alias to it
+ */
+# ifdef WIN32
+#  define VIR_MOCKABLE(ret, name, ...) \
+      ret name(__VA_ARGS__) __attribute__((noinline, noclone, __alias__(#name "Impl"))); \
+      ret name ## Impl (__VA_ARGS__); \
+      ret name ## Impl (__VA_ARGS__)
+# else
+#  if __GNUC_PREREQ(4, 5)
+#   define VIR_MOCKABLE(ret, name, ...) \
+      ret name(__VA_ARGS__) __attribute__((noinline, noclone, weak, __alias__(#name "Impl"))); \
+      ret name ## Impl (__VA_ARGS__); \
+      ret name ## Impl (__VA_ARGS__)
+#  else
+#   define VIR_MOCKABLE(ret, name, ...) \
+      ret name(__VA_ARGS__) __attribute__((noinline, weak, __alias__(#name "Impl"))); \
+      ret name ## Impl (__VA_ARGS__); \
+      ret name ## Impl (__VA_ARGS__)
+#  endif
+# endif
+
+/*
  * Use this when passing possibly-NULL strings to printf-a-likes.
  */
 # define NULLSTR(s) ((s) ? (s) : "<null>")
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index db9f9b8..d4316bc 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -1148,10 +1148,11 @@ virQEMUCapsInitGuestFromBinary(virCapsPtr caps,
 }
 
 
-virCPUDefPtr
-virQEMUCapsProbeHostCPUForEmulator(virCapsPtr caps,
-                                   virQEMUCapsPtr qemuCaps,
-                                   virDomainVirtType type)
+VIR_MOCKABLE(virCPUDefPtr,
+             virQEMUCapsProbeHostCPUForEmulator,
+             virCapsPtr caps,
+             virQEMUCapsPtr qemuCaps,
+             virDomainVirtType type)
 {
     size_t nmodels;
     char **models;
diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h
index 6cc189e..a7c92fd 100644
--- a/src/qemu/qemu_capspriv.h
+++ b/src/qemu/qemu_capspriv.h
@@ -95,7 +95,7 @@ virQEMUCapsSetCPUModelInfo(virQEMUCapsPtr qemuCaps,
 virCPUDefPtr
 virQEMUCapsProbeHostCPUForEmulator(virCapsPtr caps,
                                    virQEMUCapsPtr qemuCaps,
-                                   virDomainVirtType type) ATTRIBUTE_MOCKABLE;
+                                   virDomainVirtType type);
 
 void
 virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps,
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index d228c8a..db872bb 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -1425,11 +1425,13 @@ int virNetSocketGetPort(virNetSocketPtr sock)
 
 
 #if defined(SO_PEERCRED)
-int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
-                                uid_t *uid,
-                                gid_t *gid,
-                                pid_t *pid,
-                                unsigned long long *timestamp)
+VIR_MOCKABLE(int,
+             virNetSocketGetUNIXIdentity,
+             virNetSocketPtr sock,
+             uid_t *uid,
+             gid_t *gid,
+             pid_t *pid,
+             unsigned long long *timestamp)
 {
 # if defined(HAVE_STRUCT_SOCKPEERCRED)
     struct sockpeercred cr;
@@ -1482,11 +1484,13 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
 #  define VIR_SOL_PEERCRED 0
 # endif
 
-int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
-                                uid_t *uid,
-                                gid_t *gid,
-                                pid_t *pid,
-                                unsigned long long *timestamp)
+VIR_MOCKABLE(int,
+             virNetSocketGetUNIXIdentity,
+             virNetSocketPtr sock,
+             uid_t *uid,
+             gid_t *gid,
+             pid_t *pid,
+             unsigned long long *timestamp)
 {
     struct xucred cr;
     socklen_t cr_len = sizeof(cr);
@@ -1550,11 +1554,13 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
     return ret;
 }
 #else
-int virNetSocketGetUNIXIdentity(virNetSocketPtr sock ATTRIBUTE_UNUSED,
-                                uid_t *uid ATTRIBUTE_UNUSED,
-                                gid_t *gid ATTRIBUTE_UNUSED,
-                                pid_t *pid ATTRIBUTE_UNUSED,
-                                unsigned long long *timestamp ATTRIBUTE_UNUSED)
+VIR_MOCKABLE(int,
+             virNetSocketGetUNIXIdentity,
+             virNetSocketPtr sock ATTRIBUTE_UNUSED,
+             uid_t *uid ATTRIBUTE_UNUSED,
+             gid_t *gid ATTRIBUTE_UNUSED,
+             pid_t *pid ATTRIBUTE_UNUSED,
+             unsigned long long *timestamp ATTRIBUTE_UNUSED)
 {
     /* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
     virReportSystemError(ENOSYS, "%s",
@@ -1564,8 +1570,10 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock ATTRIBUTE_UNUSED,
 #endif
 
 #ifdef WITH_SELINUX
-int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
-                                  char **context)
+VIR_MOCKABLE(int,
+             virNetSocketGetSELinuxContext,
+             virNetSocketPtr sock,
+             char **context)
 {
     security_context_t seccon = NULL;
     int ret = -1;
@@ -1593,8 +1601,10 @@ int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
     return ret;
 }
 #else
-int virNetSocketGetSELinuxContext(virNetSocketPtr sock ATTRIBUTE_UNUSED,
-                                  char **context)
+VIR_MOCKABLE(int,
+             virNetSocketGetSELinuxContext,
+             virNetSocketPtr sock ATTRIBUTE_UNUSED,
+             char **context)
 {
     *context = NULL;
     return 0;
diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h
index 3c2945e..1e75ee6 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -136,11 +136,9 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
                                 uid_t *uid,
                                 gid_t *gid,
                                 pid_t *pid,
-                                unsigned long long *timestamp)
-    ATTRIBUTE_MOCKABLE;
+                                unsigned long long *timestamp);
 int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
-                                  char **context)
-    ATTRIBUTE_MOCKABLE;
+                                  char **context);
 
 int virNetSocketSetBlocking(virNetSocketPtr sock,
                             bool blocking);
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 60c1121..4ac0aa9 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -985,8 +985,9 @@ virCommandNewVAList(const char *binary, va_list list)
  * be closed in the parent no later than Run/RunAsync/Free. The parent
  * should cease using the @fd when this call completes
  */
-void
-virCommandPassFD(virCommandPtr cmd, int fd, unsigned int flags)
+VIR_MOCKABLE(void,
+             virCommandPassFD,
+             virCommandPtr cmd, int fd, unsigned int flags)
 {
     int ret = 0;
 
@@ -1012,6 +1013,7 @@ virCommandPassFD(virCommandPtr cmd, int fd, unsigned int flags)
     }
 }
 
+
 /**
  * virCommandPassListenFDs:
  * @cmd: the command to modify
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index c042a53..99dcdeb 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -58,7 +58,7 @@ enum {
 
 void virCommandPassFD(virCommandPtr cmd,
                       int fd,
-                      unsigned int flags) ATTRIBUTE_MOCKABLE;
+                      unsigned int flags);
 
 void virCommandPassListenFDs(virCommandPtr cmd);
 
diff --git a/src/util/vircrypto.c b/src/util/vircrypto.c
index 48b04fc..13cacfb 100644
--- a/src/util/vircrypto.c
+++ b/src/util/vircrypto.c
@@ -300,8 +300,9 @@ virCryptoEncryptData(virCryptoCipher algorithm,
  *
  * Returns pointer memory containing byte stream on success, NULL on failure
  */
-uint8_t *
-virCryptoGenerateRandom(size_t nbytes)
+VIR_MOCKABLE(uint8_t *,
+             virCryptoGenerateRandom,
+             size_t nbytes)
 {
     uint8_t *buf;
     int ret;
diff --git a/src/util/vircrypto.h b/src/util/vircrypto.h
index 50400c6..52ba3b3 100644
--- a/src/util/vircrypto.h
+++ b/src/util/vircrypto.h
@@ -55,6 +55,6 @@ int virCryptoEncryptData(virCryptoCipher algorithm,
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6)
     ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(9) ATTRIBUTE_RETURN_CHECK;
 
-uint8_t *virCryptoGenerateRandom(size_t nbytes) ATTRIBUTE_MOCKABLE;
+uint8_t *virCryptoGenerateRandom(size_t nbytes);
 
 #endif /* __VIR_CRYPTO_H__ */
diff --git a/src/util/virfile.c b/src/util/virfile.c
index d444b32..b612ad5 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -1824,8 +1824,9 @@ virFileIsDir(const char *path)
  * Returns true if the file exists, false if it doesn't, setting errno
  * appropriately.
  */
-bool
-virFileExists(const char *path)
+VIR_MOCKABLE(bool,
+             virFileExists,
+             const char *path)
 {
     return access(path, F_OK) == 0;
 }
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 32c9115..40034f0 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -188,7 +188,7 @@ void virFileActivateDirOverride(const char *argv0)
 
 off_t virFileLength(const char *path, int fd) ATTRIBUTE_NONNULL(1);
 bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1);
-bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1) ATTRIBUTE_MOCKABLE;
+bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1);
 bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1);
 
 enum {
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index c485a97..4d63842 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -1112,8 +1112,9 @@ virHostCPUGetMap(unsigned char **cpumap,
  *
  * Returns the number of threads per subcore if subcores are in use, zero
  * if subcores are not in use, and a negative value on error */
-int
-virHostCPUGetThreadsPerSubcore(virArch arch)
+VIR_MOCKABLE(int,
+             virHostCPUGetThreadsPerSubcore,
+             virArch arch)
 {
     int threads_per_subcore = 0;
     int kvmfd;
@@ -1167,8 +1168,9 @@ virHostCPUGetThreadsPerSubcore(virArch arch ATTRIBUTE_UNUSED)
 #endif /* HAVE_LINUX_KVM_H && defined(KVM_CAP_PPC_SMT) */
 
 #if HAVE_LINUX_KVM_H
-int
-virHostCPUGetKVMMaxVCPUs(void)
+VIR_MOCKABLE(int,
+             virHostCPUGetKVMMaxVCPUs,
+             void)
 {
     int fd;
     int ret;
diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h
index 3b30a0d..e9c22ee 100644
--- a/src/util/virhostcpu.h
+++ b/src/util/virhostcpu.h
@@ -38,7 +38,7 @@ bool virHostCPUHasBitmap(void);
 virBitmapPtr virHostCPUGetPresentBitmap(void);
 virBitmapPtr virHostCPUGetOnlineBitmap(void);
 int virHostCPUGetCount(void);
-int virHostCPUGetThreadsPerSubcore(virArch arch) ATTRIBUTE_MOCKABLE;
+int virHostCPUGetThreadsPerSubcore(virArch arch);
 
 int virHostCPUGetMap(unsigned char **cpumap,
                      unsigned int *online,
@@ -51,7 +51,7 @@ int virHostCPUGetInfo(virArch hostarch,
                       unsigned int *cores,
                       unsigned int *threads);
 
-int virHostCPUGetKVMMaxVCPUs(void) ATTRIBUTE_MOCKABLE;
+int virHostCPUGetKVMMaxVCPUs(void);
 
 int virHostCPUStatsAssign(virNodeCPUStatsPtr param,
                           const char *name,
diff --git a/src/util/virmacaddr.c b/src/util/virmacaddr.c
index 7afe032..29d6980 100644
--- a/src/util/virmacaddr.c
+++ b/src/util/virmacaddr.c
@@ -223,8 +223,10 @@ virMacAddrParseHex(const char *str, virMacAddrPtr addr)
     return 0;
 }
 
-void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],
-                        virMacAddrPtr addr)
+VIR_MOCKABLE(void,
+             virMacAddrGenerate,
+             const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],
+             virMacAddrPtr addr)
 {
     addr->addr[0] = prefix[0];
     addr->addr[1] = prefix[1];
diff --git a/src/util/virmacaddr.h b/src/util/virmacaddr.h
index 79492cd..ae26867 100644
--- a/src/util/virmacaddr.h
+++ b/src/util/virmacaddr.h
@@ -48,7 +48,7 @@ void virMacAddrGetRaw(const virMacAddr *src, unsigned char dst[VIR_MAC_BUFLEN]);
 const char *virMacAddrFormat(const virMacAddr *addr,
                              char *str);
 void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],
-                        virMacAddrPtr addr) ATTRIBUTE_MOCKABLE;
+                        virMacAddrPtr addr);
 int virMacAddrParse(const char* str,
                     virMacAddrPtr addr) ATTRIBUTE_RETURN_CHECK;
 int virMacAddrParseHex(const char* str,
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 90b7bee..7c1ec5c 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -346,9 +346,9 @@ virNetDevSetMACInternal(const char *ifname,
 #endif
 
 
-int
-virNetDevSetMAC(const char *ifname,
-                const virMacAddr *macaddr)
+VIR_MOCKABLE(int,
+             virNetDevSetMAC,
+             const char *ifname, const virMacAddr *macaddr)
 {
     return virNetDevSetMACInternal(ifname, macaddr, false);
 }
@@ -686,9 +686,9 @@ virNetDevSetIFFlag(const char *ifname,
  *
  * Returns 0 in case of success or -1 on error.
  */
-int
-virNetDevSetOnline(const char *ifname,
-                   bool online)
+VIR_MOCKABLE(int,
+             virNetDevSetOnline,
+             const char *ifname, bool online)
 {
 
     return virNetDevSetIFFlag(ifname, VIR_IFF_UP, online);
@@ -1122,9 +1122,9 @@ int virNetDevValidateConfig(const char *ifname ATTRIBUTE_UNUSED,
 
 #ifdef __linux__
 
-int
-virNetDevSysfsFile(char **pf_sysfs_device_link, const char *ifname,
-                   const char *file)
+VIR_MOCKABLE(int,
+             virNetDevSysfsFile,
+             char **pf_sysfs_device_link, const char *ifname, const char *file)
 {
 
     if (virAsprintf(pf_sysfs_device_link, SYSFS_NET_DIR "%s/%s", ifname, file) < 0)
@@ -3268,8 +3268,9 @@ int virNetDevSetCoalesce(const char *ifname,
  * This function executes script for new tap device created by libvirt.
  * Returns 0 in case of success or -1 on failure
  */
-int
-virNetDevRunEthernetScript(const char *ifname, const char *script)
+VIR_MOCKABLE(int,
+             virNetDevRunEthernetScript,
+             const char *ifname, const char *script)
 {
     virCommandPtr cmd;
     int ret;
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 2e9a9c4..c2c09af 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -156,7 +156,7 @@ int virNetDevExists(const char *brname)
 
 int virNetDevSetOnline(const char *ifname,
                        bool online)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 int virNetDevGetOnline(const char *ifname,
                       bool *online)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
@@ -164,7 +164,7 @@ int virNetDevGetOnline(const char *ifname,
 
 int virNetDevSetMAC(const char *ifname,
                     const virMacAddr *macaddr)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 int virNetDevGetMAC(const char *ifname,
                     virMacAddrPtr macaddr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
@@ -303,8 +303,7 @@ int virNetDevSysfsFile(char **pf_sysfs_device_link,
                        const char *ifname,
                        const char *file)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_RETURN_CHECK;
 
-int virNetDevRunEthernetScript(const char *ifname, const char *script)
-    ATTRIBUTE_MOCKABLE;
+int virNetDevRunEthernetScript(const char *ifname, const char *script);
 #endif /* __VIR_NETDEV_H__ */
diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c
index bf98ed8..6dcd2e8 100644
--- a/src/util/virnetdevip.c
+++ b/src/util/virnetdevip.c
@@ -163,11 +163,10 @@ virNetDevCreateNetlinkAddressMessage(int messageType,
  *
  * Returns 0 in case of success or -1 in case of error.
  */
-int
-virNetDevIPAddrAdd(const char *ifname,
-                   virSocketAddr *addr,
-                   virSocketAddr *peer,
-                   unsigned int prefix)
+VIR_MOCKABLE(int,
+             virNetDevIPAddrAdd,
+             const char *ifname, virSocketAddr *addr,
+             virSocketAddr *peer, unsigned int prefix)
 {
     virSocketAddr *broadcast = NULL;
     int ret = -1;
diff --git a/src/util/virnetdevip.h b/src/util/virnetdevip.h
index 972a49a..cc466ca 100644
--- a/src/util/virnetdevip.h
+++ b/src/util/virnetdevip.h
@@ -67,7 +67,7 @@ int virNetDevIPAddrAdd(const char *ifname,
                        virSocketAddr *addr,
                        virSocketAddr *peer,
                        unsigned int prefix)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 int virNetDevIPRouteAdd(const char *ifname,
                         virSocketAddrPtr addr,
                         unsigned int prefix,
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
index a5ecfb6..ab292a4 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -382,7 +382,7 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
 }
 
 /**
- * virNetDevOpenvswitchVhostuserGetIfname:
+ * virNetDevOpenvswitchGetVhostuserIfname:
  * @path: the path of the unix socket
  * @ifname: the retrieved name of the interface
  *
@@ -392,9 +392,9 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
  *          0 if it is not, but no other error occurred,
  *         -1 otherwise.
  */
-int
-virNetDevOpenvswitchGetVhostuserIfname(const char *path,
-                                       char **ifname)
+VIR_MOCKABLE(int,
+             virNetDevOpenvswitchGetVhostuserIfname,
+             const char *path, char **ifname)
 {
     virCommandPtr cmd = NULL;
     char *tmpIfname = NULL;
diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
index dc677ca..7380a2d 100644
--- a/src/util/virnetdevopenvswitch.h
+++ b/src/util/virnetdevopenvswitch.h
@@ -59,6 +59,6 @@ int virNetDevOpenvswitchInterfaceStats(const char *ifname,
 
 int virNetDevOpenvswitchGetVhostuserIfname(const char *path,
                                            char **ifname)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 
 #endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 175dc2b..93cb65d 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -98,8 +98,9 @@ virNetDevTapGetName(int tapfd ATTRIBUTE_UNUSED, char **ifname ATTRIBUTE_UNUSED)
  * Returns the proper interface name or NULL if no corresponding interface
  * found.
  */
-char*
-virNetDevTapGetRealDeviceName(char *ifname ATTRIBUTE_UNUSED)
+VIR_MOCKABLE(char *,
+             virNetDevTapGetRealDeviceName,
+             char *ifname ATTRIBUTE_UNUSED)
 {
 #ifdef TAPGIFNAME
     char *ret = NULL;
@@ -238,11 +239,13 @@ virNetDevProbeVnetHdr(int tapfd)
  *
  * Returns 0 in case of success or -1 on failure.
  */
-int virNetDevTapCreate(char **ifname,
-                       const char *tunpath,
-                       int *tapfd,
-                       size_t tapfdSize,
-                       unsigned int flags)
+VIR_MOCKABLE(int,
+             virNetDevTapCreate,
+             char **ifname,
+             const char *tunpath,
+             int *tapfd,
+             size_t tapfdSize,
+             unsigned int flags)
 {
     size_t i;
     struct ifreq ifr;
@@ -608,19 +611,21 @@ virNetDevTapAttachBridge(const char *tapname,
  *
  * Returns 0 in case of success or -1 on failure
  */
-int virNetDevTapCreateInBridgePort(const char *brname,
-                                   char **ifname,
-                                   const virMacAddr *macaddr,
-                                   const unsigned char *vmuuid,
-                                   const char *tunpath,
-                                   int *tapfd,
-                                   size_t tapfdSize,
-                                   virNetDevVPortProfilePtr virtPortProfile,
-                                   virNetDevVlanPtr virtVlan,
-                                   virNetDevCoalescePtr coalesce,
-                                   unsigned int mtu,
-                                   unsigned int *actualMTU,
-                                   unsigned int flags)
+VIR_MOCKABLE(int,
+             virNetDevTapCreateInBridgePort,
+             const char *brname,
+             char **ifname,
+             const virMacAddr *macaddr,
+             const unsigned char *vmuuid,
+             const char *tunpath,
+             int *tapfd,
+             size_t tapfdSize,
+             virNetDevVPortProfilePtr virtPortProfile,
+             virNetDevVlanPtr virtVlan,
+             virNetDevCoalescePtr coalesce,
+             unsigned int mtu,
+             unsigned int *actualMTU,
+             unsigned int flags)
 {
     virMacAddr tapmac;
     char macaddrstr[VIR_MAC_STRING_BUFLEN];
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index 1c4343e..bd5ec14 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -39,7 +39,7 @@ int virNetDevTapCreate(char **ifname,
                        int *tapfd,
                        size_t tapfdSize,
                        unsigned int flags)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
 int virNetDevTapDelete(const char *ifname,
                        const char *tunpath)
@@ -49,7 +49,7 @@ int virNetDevTapGetName(int tapfd, char **ifname)
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 
 char* virNetDevTapGetRealDeviceName(char *ifname)
-      ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+      ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
 typedef enum {
    VIR_NETDEV_TAP_CREATE_NONE = 0,
@@ -89,7 +89,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    unsigned int *actualMTU,
                                    unsigned int flags)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_RETURN_CHECK;
 
 int virNetDevTapInterfaceStats(const char *ifname,
                                virDomainInterfaceStatsPtr stats)
diff --git a/src/util/virnuma.c b/src/util/virnuma.c
index bebe301..6300bc1 100644
--- a/src/util/virnuma.c
+++ b/src/util/virnuma.c
@@ -160,8 +160,9 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
     return ret;
 }
 
-bool
-virNumaIsAvailable(void)
+VIR_MOCKABLE(bool,
+             virNumaIsAvailable,
+             void)
 {
     return numa_available() != -1;
 }
@@ -174,8 +175,9 @@ virNumaIsAvailable(void)
  *
  * Returns the highest NUMA node id on success, -1 on error.
  */
-int
-virNumaGetMaxNode(void)
+VIR_MOCKABLE(int,
+             virNumaGetMaxNode,
+             void)
 {
     int ret;
 
@@ -207,10 +209,11 @@ virNumaGetMaxNode(void)
  *
  * Returns 0 on success, -1 on error. Does not report errors.
  */
-int
-virNumaGetNodeMemory(int node,
-                     unsigned long long *memsize,
-                     unsigned long long *memfree)
+VIR_MOCKABLE(int,
+             virNumaGetNodeMemory,
+             int node,
+             unsigned long long *memsize,
+             unsigned long long *memfree)
 {
     long long node_size;
     long long node_free;
@@ -248,9 +251,10 @@ virNumaGetNodeMemory(int node,
 # define n_bits(var) (8 * sizeof(var))
 # define MASK_CPU_ISSET(mask, cpu) \
   (((mask)[((cpu) / n_bits(*(mask)))] >> ((cpu) % n_bits(*(mask)))) & 1)
-int
-virNumaGetNodeCPUs(int node,
-                   virBitmapPtr *cpus)
+VIR_MOCKABLE(int,
+             virNumaGetNodeCPUs,
+             int node,
+             virBitmapPtr *cpus)
 {
     unsigned long *mask = NULL;
     unsigned long *allonesmask = NULL;
@@ -321,15 +325,17 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode ATTRIBUTE_UNUSED,
     return 0;
 }
 
-bool
-virNumaIsAvailable(void)
+VIR_MOCKABLE(bool,
+             virNumaIsAvailable,
+             void)
 {
     return false;
 }
 
 
-int
-virNumaGetMaxNode(void)
+VIR_MOCKABLE(int,
+             virNumaGetMaxNode,
+             void)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("NUMA isn't available on this host"));
@@ -337,10 +343,11 @@ virNumaGetMaxNode(void)
 }
 
 
-int
-virNumaGetNodeMemory(int node ATTRIBUTE_UNUSED,
-                     unsigned long long *memsize,
-                     unsigned long long *memfree)
+VIR_MOCKABLE(int,
+             virNumaGetNodeMemory,
+             int node ATTRIBUTE_UNUSED,
+             unsigned long long *memsize,
+             unsigned long long *memfree)
 {
     if (memsize)
         *memsize = 0;
@@ -353,9 +360,10 @@ virNumaGetNodeMemory(int node ATTRIBUTE_UNUSED,
 }
 
 
-int
-virNumaGetNodeCPUs(int node ATTRIBUTE_UNUSED,
-                   virBitmapPtr *cpus)
+VIR_MOCKABLE(int,
+             virNumaGetNodeCPUs,
+             int node ATTRIBUTE_UNUSED,
+             virBitmapPtr *cpus)
 {
     *cpus = NULL;
 
@@ -390,8 +398,9 @@ virNumaGetMaxCPUs(void)
  * Returns: true if @node is available,
  *          false if @node doesn't exist
  */
-bool
-virNumaNodeIsAvailable(int node)
+VIR_MOCKABLE(bool,
+             virNumaNodeIsAvailable,
+             int node)
 {
     return numa_bitmask_isbitset(numa_nodes_ptr, node);
 }
@@ -416,10 +425,11 @@ virNumaNodeIsAvailable(int node)
  *
  * Returns 0 on success, -1 otherwise.
  */
-int
-virNumaGetDistances(int node,
-                    int **distances,
-                    int *ndistances)
+VIR_MOCKABLE(int,
+             virNumaGetDistances,
+             int node,
+             int **distances,
+             int *ndistances)
 {
     int ret = -1;
     int max_node;
@@ -454,8 +464,9 @@ virNumaGetDistances(int node,
 
 #else /* !(WITH_NUMACTL && HAVE_NUMA_BITMASK_ISBITSET) */
 
-bool
-virNumaNodeIsAvailable(int node)
+VIR_MOCKABLE(bool,
+             virNumaNodeIsAvailable,
+             int node)
 {
     int max_node = virNumaGetMaxNode();
 
@@ -467,10 +478,11 @@ virNumaNodeIsAvailable(int node)
 }
 
 
-int
-virNumaGetDistances(int node ATTRIBUTE_UNUSED,
-                    int **distances,
-                    int *ndistances)
+VIR_MOCKABLE(int,
+             virNumaGetDistances,
+             int node ATTRIBUTE_UNUSED,
+             int **distances,
+             int *ndistances)
 {
     *distances = NULL;
     *ndistances = 0;
@@ -706,12 +718,13 @@ virNumaGetPageInfo(int node,
  *
  * Returns 0 on success, -1 otherwise.
  */
-int
-virNumaGetPages(int node,
-                unsigned int **pages_size,
-                unsigned int **pages_avail,
-                unsigned int **pages_free,
-                size_t *npages)
+VIR_MOCKABLE(int,
+             virNumaGetPages,
+             int node,
+             unsigned int **pages_size,
+             unsigned int **pages_avail,
+             unsigned int **pages_free,
+             size_t *npages)
 {
     int ret = -1;
     char *path = NULL;
@@ -943,12 +956,13 @@ virNumaGetPageInfo(int node ATTRIBUTE_UNUSED,
 }
 
 
-int
-virNumaGetPages(int node ATTRIBUTE_UNUSED,
-                unsigned int **pages_size ATTRIBUTE_UNUSED,
-                unsigned int **pages_avail ATTRIBUTE_UNUSED,
-                unsigned int **pages_free ATTRIBUTE_UNUSED,
-                size_t *npages ATTRIBUTE_UNUSED)
+VIR_MOCKABLE(int,
+             virNumaGetPages,
+             int node ATTRIBUTE_UNUSED,
+             unsigned int **pages_size ATTRIBUTE_UNUSED,
+             unsigned int **pages_avail ATTRIBUTE_UNUSED,
+             unsigned int **pages_free ATTRIBUTE_UNUSED,
+             size_t *npages ATTRIBUTE_UNUSED)
 {
     virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                    _("page info is not supported on this platform"));
@@ -968,8 +982,9 @@ virNumaSetPagePoolSize(int node ATTRIBUTE_UNUSED,
 }
 #endif /* #ifdef __linux__ */
 
-bool
-virNumaNodesetIsAvailable(virBitmapPtr nodeset)
+VIR_MOCKABLE(bool,
+             virNumaNodesetIsAvailable,
+             virBitmapPtr nodeset)
 {
     ssize_t bit = -1;
 
diff --git a/src/util/virnuma.h b/src/util/virnuma.h
index 62b89e9..f3eef32 100644
--- a/src/util/virnuma.h
+++ b/src/util/virnuma.h
@@ -34,20 +34,20 @@ int virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
                              virBitmapPtr nodeset);
 
 virBitmapPtr virNumaGetHostMemoryNodeset(void);
-bool virNumaNodesetIsAvailable(virBitmapPtr nodeset) ATTRIBUTE_MOCKABLE;
-bool virNumaIsAvailable(void) ATTRIBUTE_MOCKABLE;
-int virNumaGetMaxNode(void) ATTRIBUTE_MOCKABLE;
-bool virNumaNodeIsAvailable(int node) ATTRIBUTE_MOCKABLE;
+bool virNumaNodesetIsAvailable(virBitmapPtr nodeset);
+bool virNumaIsAvailable(void);
+int virNumaGetMaxNode(void);
+bool virNumaNodeIsAvailable(int node);
 int virNumaGetDistances(int node,
                         int **distances,
-                        int *ndistances) ATTRIBUTE_MOCKABLE;
+                        int *ndistances);
 int virNumaGetNodeMemory(int node,
                          unsigned long long *memsize,
-                         unsigned long long *memfree) ATTRIBUTE_MOCKABLE;
+                         unsigned long long *memfree);
 
 unsigned int virNumaGetMaxCPUs(void);
 
-int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus) ATTRIBUTE_MOCKABLE;
+int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus);
 
 int virNumaGetPageInfo(int node,
                        unsigned int page_size,
@@ -59,7 +59,7 @@ int virNumaGetPages(int node,
                     unsigned int **pages_avail,
                     unsigned int **pages_free,
                     size_t *npages)
-    ATTRIBUTE_NONNULL(5) ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(5);
 int virNumaSetPagePoolSize(int node,
                            unsigned int page_size,
                            unsigned long long page_count,
diff --git a/src/util/virrandom.c b/src/util/virrandom.c
index 41daa40..90d6905 100644
--- a/src/util/virrandom.c
+++ b/src/util/virrandom.c
@@ -99,7 +99,9 @@ VIR_ONCE_GLOBAL_INIT(virRandom)
  *
  * Return: a random number with @nbits entropy
  */
-uint64_t virRandomBits(int nbits)
+VIR_MOCKABLE(uint64_t,
+             virRandomBits,
+             int nbits)
 {
     uint64_t ret = 0;
     int32_t bits;
@@ -170,9 +172,10 @@ uint32_t virRandomInt(uint32_t max)
  *
  * Returns 0 on success or an errno on failure
  */
-int
-virRandomBytes(unsigned char *buf,
-               size_t buflen)
+VIR_MOCKABLE(int,
+             virRandomBytes,
+             unsigned char *buf,
+             size_t buflen)
 {
     int fd;
 
@@ -205,9 +208,10 @@ virRandomBytes(unsigned char *buf,
 #define XEN_OUI "00163e"
 
 
-int
-virRandomGenerateWWN(char **wwn,
-                     const char *virt_type)
+VIR_MOCKABLE(int,
+             virRandomGenerateWWN,
+             char **wwn,
+             const char *virt_type)
 {
     const char *oui = NULL;
 
diff --git a/src/util/virrandom.h b/src/util/virrandom.h
index 990a456..f457d2d 100644
--- a/src/util/virrandom.h
+++ b/src/util/virrandom.h
@@ -24,11 +24,11 @@
 
 # include "internal.h"
 
-uint64_t virRandomBits(int nbits) ATTRIBUTE_MOCKABLE;
+uint64_t virRandomBits(int nbits);
 double virRandom(void);
 uint32_t virRandomInt(uint32_t max);
 int virRandomBytes(unsigned char *buf, size_t buflen)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_MOCKABLE;
-int virRandomGenerateWWN(char **wwn, const char *virt_type) ATTRIBUTE_MOCKABLE;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+int virRandomGenerateWWN(char **wwn, const char *virt_type);
 
 #endif /* __VIR_RANDOM_H__ */
diff --git a/src/util/virscsi.c b/src/util/virscsi.c
index 22f2677..d6fe4b7 100644
--- a/src/util/virscsi.c
+++ b/src/util/virscsi.c
@@ -109,12 +109,13 @@ virSCSIDeviceGetAdapterId(const char *adapter,
     return -1;
 }
 
-char *
-virSCSIDeviceGetSgName(const char *sysfs_prefix,
-                       const char *adapter,
-                       unsigned int bus,
-                       unsigned int target,
-                       unsigned long long unit)
+VIR_MOCKABLE(char *,
+             virSCSIDeviceGetSgName,
+             const char *sysfs_prefix,
+             const char *adapter,
+             unsigned int bus,
+             unsigned int target,
+             unsigned long long unit)
 {
     DIR *dir = NULL;
     struct dirent *entry;
diff --git a/src/util/virscsi.h b/src/util/virscsi.h
index eed563d..7d88d4e 100644
--- a/src/util/virscsi.h
+++ b/src/util/virscsi.h
@@ -37,7 +37,7 @@ char *virSCSIDeviceGetSgName(const char *sysfs_prefix,
                              const char *adapter,
                              unsigned int bus,
                              unsigned int target,
-                             unsigned long long unit) ATTRIBUTE_MOCKABLE;
+                             unsigned long long unit);
 char *virSCSIDeviceGetDevName(const char *sysfs_prefix,
                               const char *adapter,
                               unsigned int bus,
diff --git a/src/util/virscsivhost.c b/src/util/virscsivhost.c
index dc7df75..32828f7 100644
--- a/src/util/virscsivhost.c
+++ b/src/util/virscsivhost.c
@@ -83,8 +83,9 @@ virSCSIVHostOnceInit(void)
 VIR_ONCE_GLOBAL_INIT(virSCSIVHost)
 
 
-int
-virSCSIVHostOpenVhostSCSI(int *vhostfd)
+VIR_MOCKABLE(int,
+             virSCSIVHostOpenVhostSCSI,
+             int *vhostfd)
 {
     if (!virFileExists(VHOST_SCSI_DEVICE))
         goto error;
diff --git a/src/util/virscsivhost.h b/src/util/virscsivhost.h
index f9272a6..6018b83 100644
--- a/src/util/virscsivhost.h
+++ b/src/util/virscsivhost.h
@@ -61,6 +61,6 @@ void virSCSIVHostDeviceGetUsedBy(virSCSIVHostDevicePtr dev,
                                  const char **drv_name,
                                  const char **dom_name);
 void virSCSIVHostDeviceFree(virSCSIVHostDevicePtr dev);
-int virSCSIVHostOpenVhostSCSI(int *vhostfd) ATTRIBUTE_MOCKABLE;
+int virSCSIVHostOpenVhostSCSI(int *vhostfd);
 
 #endif /* __VIR_SCSIHOST_H__ */
diff --git a/src/util/virtpm.c b/src/util/virtpm.c
index 6d9b065..07db753 100644
--- a/src/util/virtpm.c
+++ b/src/util/virtpm.c
@@ -38,8 +38,9 @@
  *
  * Create the cancel path given the path to the TPM device
  */
-char *
-virTPMCreateCancelPath(const char *devpath)
+VIR_MOCKABLE(char *,
+             virTPMCreateCancelPath,
+             const char *devpath)
 {
     char *path = NULL;
     const char *dev;
diff --git a/src/util/virtpm.h b/src/util/virtpm.h
index 7067bb5..fe71307 100644
--- a/src/util/virtpm.h
+++ b/src/util/virtpm.h
@@ -22,6 +22,6 @@
 #ifndef __VIR_TPM_H__
 # define __VIR_TPM_H__
 
-char *virTPMCreateCancelPath(const char *devpath) ATTRIBUTE_MOCKABLE;
+char *virTPMCreateCancelPath(const char *devpath);
 
 #endif /* __VIR_TPM_H__ */
diff --git a/src/util/virutil.c b/src/util/virutil.c
index e08f9fa..81bfba7 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -884,14 +884,18 @@ char *virGetUserRuntimeDirectory(void)
     }
 }
 
-char *virGetUserName(uid_t uid)
+VIR_MOCKABLE(char *,
+             virGetUserName,
+             uid_t uid)
 {
     char *ret;
     virGetUserEnt(uid, &ret, NULL, NULL, NULL, false);
     return ret;
 }
 
-char *virGetGroupName(gid_t gid)
+VIR_MOCKABLE(char *,
+             virGetGroupName,
+             gid_t gid)
 {
     return virGetGroupEnt(gid);
 }
@@ -1340,8 +1344,9 @@ virGetUserRuntimeDirectory(void)
 }
 # endif /* ! HAVE_GETPWUID_R && ! WIN32 */
 
-char *
-virGetUserName(uid_t uid ATTRIBUTE_UNUSED)
+VIR_MOCKABLE(char *,
+             virGetUserName,
+             uid_t uid ATTRIBUTE_UNUSED)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR,
                    "%s", _("virGetUserName is not available"));
@@ -1379,8 +1384,9 @@ virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED,
     return -1;
 }
 
-char *
-virGetGroupName(gid_t gid ATTRIBUTE_UNUSED)
+VIR_MOCKABLE(char *,
+             virGetGroupName,
+             gid_t gid ATTRIBUTE_UNUSED)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR,
                    "%s", _("virGetGroupName is not available"));
@@ -1908,12 +1914,16 @@ virGetListenFDs(void)
 #endif /* WIN32 */
 
 #ifndef WIN32
-long virGetSystemPageSize(void)
+VIR_MOCKABLE(long,
+             virGetSystemPageSize,
+             void)
 {
     return sysconf(_SC_PAGESIZE);
 }
 #else /* WIN32 */
-long virGetSystemPageSize(void)
+VIR_MOCKABLE(long,
+             virGetSystemPageSize,
+             void)
 {
     errno = ENOSYS;
     return -1;
@@ -1959,12 +1969,11 @@ virMemoryLimitIsSet(unsigned long long value)
  * @capped: whether the value must fit into unsigned long
  *   (long long is assumed otherwise)
  *
- * Note: This function is mocked in tests/qemuxml2argvmock.c for test stability
- *
  * Returns the maximum possible memory value in bytes.
  */
-unsigned long long
-virMemoryMaxValue(bool capped)
+VIR_MOCKABLE(unsigned long long,
+             virMemoryMaxValue,
+             bool capped)
 {
     /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit
      * machines, our bound is off_t (2^63).  */
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 35e5ca3..3bbe29e 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -139,8 +139,8 @@ char *virGetUserConfigDirectory(void);
 char *virGetUserCacheDirectory(void);
 char *virGetUserRuntimeDirectory(void);
 char *virGetUserShell(uid_t uid);
-char *virGetUserName(uid_t uid) ATTRIBUTE_MOCKABLE;
-char *virGetGroupName(gid_t gid) ATTRIBUTE_MOCKABLE;
+char *virGetUserName(uid_t uid);
+char *virGetGroupName(gid_t gid);
 int virGetGroupList(uid_t uid, gid_t group, gid_t **groups)
     ATTRIBUTE_NONNULL(3);
 int virGetUserID(const char *name,
@@ -201,12 +201,12 @@ verify((int)VIR_TRISTATE_BOOL_ABSENT == (int)VIR_TRISTATE_SWITCH_ABSENT);
 
 unsigned int virGetListenFDs(void);
 
-long virGetSystemPageSize(void) ATTRIBUTE_MOCKABLE;
-long virGetSystemPageSizeKB(void) ATTRIBUTE_MOCKABLE;
+long virGetSystemPageSize(void);
+long virGetSystemPageSizeKB(void);
 
 unsigned long long virMemoryLimitTruncate(unsigned long long value);
 bool virMemoryLimitIsSet(unsigned long long value);
-unsigned long long virMemoryMaxValue(bool ulong) ATTRIBUTE_MOCKABLE;
+unsigned long long virMemoryMaxValue(bool ulong);
 
 /**
  * VIR_ASSIGN_IS_OVERFLOW:
diff --git a/src/util/viruuid.c b/src/util/viruuid.c
index 3cbaae0..30de6f5 100644
--- a/src/util/viruuid.c
+++ b/src/util/viruuid.c
@@ -68,8 +68,9 @@ virUUIDGeneratePseudoRandomBytes(unsigned char *buf,
  *
  * Returns 0 in case of success and -1 in case of failure
  */
-int
-virUUIDGenerate(unsigned char *uuid)
+VIR_MOCKABLE(int,
+             virUUIDGenerate,
+             unsigned char *uuid)
 {
     int err;
 
diff --git a/src/util/viruuid.h b/src/util/viruuid.h
index 3b41b42..5790a17 100644
--- a/src/util/viruuid.h
+++ b/src/util/viruuid.h
@@ -49,7 +49,7 @@ int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1);
 
 int virUUIDIsValid(unsigned char *uuid);
 
-int virUUIDGenerate(unsigned char *uuid) ATTRIBUTE_MOCKABLE;
+int virUUIDGenerate(unsigned char *uuid);
 
 int virUUIDParse(const char *uuidstr,
                  unsigned char *uuid)
-- 
2.9.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Rewrite the way mockable functions are handled.
Posted by Martin Kletzander 6 years, 9 months ago
On Wed, Jul 12, 2017 at 05:06:22PM +0100, Daniel P. Berrange wrote:
>Currently any mockable functions are marked with attributes
>noinline, noclone and weak. This prevents the compiler from
>optimizing away the impl of these functions.
>
>It has an unfortunate side effect with the libtool convenience
>libraries, if executables directly link to them. For example
>virlockd, virlogd both link to libvirt_util.la  When this is
>done, the linker does not consider weak symbols as being
>undefined, so it never copies them into the final executable.
>
>In this new approach, we stop annotating the headers entirely.
>Instead we create a weak function alias in the source.
>
>   int fooImpl(void) {
>      ..the real code..
>   }
>
>   int foo(void) __attribute__((noinline, noclone, weak, alias("fooImpl"))
>
>If any functions in the same file call "foo", this prevents the
>optimizer from inlining any part of fooImpl. When linking to the
>libtool convenience static library, we also get all the symbols
>present. Finally the test suite can just directly define a
>'foo' function in its source, removing the need to use LD_PRELOAD
>(though removal of LD_PRELOADS is left for a future patch).
>

What are you using for tag navigation?  With this macro-defined
functions I cannot easily jump to them (the main reason why I don't like
macros defining functions).  I would very much prefer if
ATTRIBUTE_MOCKABLE just took a parameter like this:

#define ATTRIBUTE_MOCKABLE(func) __attribute__((noinline, noclone, weak, alias(#func "Impl"))

(written by hand, don't take mu word for it working out of the box) and
the original function would be left untouched.


Also, this fails on OS X [1] and I don't really see why:

util/vircommand.c:988:1: error: only weak aliases are supported on darwin
VIR_MOCKABLE(void,
^
./internal.h:252:60: note: expanded from macro 'VIR_MOCKABLE'
      ret name(__VA_ARGS__) __attribute__((noinline, weak, __alias__(#name "Impl"))); \
                                                           ^
1 error generated.
make[3]: *** [util/libvirt_util_la-vircommand.lo] Error 1
make[3]: *** Waiting for unfinished jobs....

[1] https://travis-ci.org/nertpinx/libvirt/jobs/253136004
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Rewrite the way mockable functions are handled.
Posted by Daniel P. Berrange 6 years, 9 months ago
On Thu, Jul 13, 2017 at 01:14:12PM +0200, Martin Kletzander wrote:
> On Wed, Jul 12, 2017 at 05:06:22PM +0100, Daniel P. Berrange wrote:
> > Currently any mockable functions are marked with attributes
> > noinline, noclone and weak. This prevents the compiler from
> > optimizing away the impl of these functions.
> > 
> > It has an unfortunate side effect with the libtool convenience
> > libraries, if executables directly link to them. For example
> > virlockd, virlogd both link to libvirt_util.la  When this is
> > done, the linker does not consider weak symbols as being
> > undefined, so it never copies them into the final executable.
> > 
> > In this new approach, we stop annotating the headers entirely.
> > Instead we create a weak function alias in the source.
> > 
> >   int fooImpl(void) {
> >      ..the real code..
> >   }
> > 
> >   int foo(void) __attribute__((noinline, noclone, weak, alias("fooImpl"))
> > 
> > If any functions in the same file call "foo", this prevents the
> > optimizer from inlining any part of fooImpl. When linking to the
> > libtool convenience static library, we also get all the symbols
> > present. Finally the test suite can just directly define a
> > 'foo' function in its source, removing the need to use LD_PRELOAD
> > (though removal of LD_PRELOADS is left for a future patch).
> > 
> 
> What are you using for tag navigation?  With this macro-defined
> functions I cannot easily jump to them (the main reason why I don't like
> macros defining functions).

Grep & historic knowledge :-)

>                              I would very much prefer if
> ATTRIBUTE_MOCKABLE just took a parameter like this:
> 
> #define ATTRIBUTE_MOCKABLE(func) __attribute__((noinline, noclone, weak, alias(#func "Impl"))
> 
> (written by hand, don't take mu word for it working out of the box) and
> the original function would be left untouched.

Yeah, that is certainly a valid alternative. I was not entirely happy
with the results I get here. As long as we don't mind repeating the
arg list in both places, your approach is more attractive, despite
the duplication.

> Also, this fails on OS X [1] and I don't really see why:
> 
> util/vircommand.c:988:1: error: only weak aliases are supported on darwin
> VIR_MOCKABLE(void,
> ^
> ./internal.h:252:60: note: expanded from macro 'VIR_MOCKABLE'
>      ret name(__VA_ARGS__) __attribute__((noinline, weak, __alias__(#name "Impl"))); \

It appears clang simply doesn't support 'alias' on Darwin. 

Docs suggest that we need to use 'weakref(#name  "Impl")' so I'll have
to test whether that's viable for our usage scenario or not.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Rewrite the way mockable functions are handled.
Posted by Martin Kletzander 6 years, 9 months ago
On Thu, Jul 13, 2017 at 12:25:50PM +0100, Daniel P. Berrange wrote:
>On Thu, Jul 13, 2017 at 01:14:12PM +0200, Martin Kletzander wrote:
>> On Wed, Jul 12, 2017 at 05:06:22PM +0100, Daniel P. Berrange wrote:
>> > Currently any mockable functions are marked with attributes
>> > noinline, noclone and weak. This prevents the compiler from
>> > optimizing away the impl of these functions.
>> >
>> > It has an unfortunate side effect with the libtool convenience
>> > libraries, if executables directly link to them. For example
>> > virlockd, virlogd both link to libvirt_util.la  When this is
>> > done, the linker does not consider weak symbols as being
>> > undefined, so it never copies them into the final executable.
>> >
>> > In this new approach, we stop annotating the headers entirely.
>> > Instead we create a weak function alias in the source.
>> >
>> >   int fooImpl(void) {
>> >      ..the real code..
>> >   }
>> >
>> >   int foo(void) __attribute__((noinline, noclone, weak, alias("fooImpl"))
>> >
>> > If any functions in the same file call "foo", this prevents the
>> > optimizer from inlining any part of fooImpl. When linking to the
>> > libtool convenience static library, we also get all the symbols
>> > present. Finally the test suite can just directly define a
>> > 'foo' function in its source, removing the need to use LD_PRELOAD
>> > (though removal of LD_PRELOADS is left for a future patch).
>> >
>>
>> What are you using for tag navigation?  With this macro-defined
>> functions I cannot easily jump to them (the main reason why I don't like
>> macros defining functions).
>
>Grep & historic knowledge :-)
>
>>                              I would very much prefer if
>> ATTRIBUTE_MOCKABLE just took a parameter like this:
>>
>> #define ATTRIBUTE_MOCKABLE(func) __attribute__((noinline, noclone, weak, alias(#func "Impl"))
>>
>> (written by hand, don't take mu word for it working out of the box) and
>> the original function would be left untouched.
>
>Yeah, that is certainly a valid alternative. I was not entirely happy
>with the results I get here. As long as we don't mind repeating the
>arg list in both places, your approach is more attractive, despite
>the duplication.
>

I think we don't if we do:

#define VIR_MOCKABLE(ret, name) typeof(name ## Impl) name \
    __attribute__((noinline, weak, __alias__(#name "Impl")));

or can't this be done for functions?  It worked when I tried it now.

I have one more idea, though.  So that we don't have to double-type the
actual definition of the Impl function, we can make it static.  What if
we make *all* functions static and only add weak aliases to those that
are supposed to be used outside the file?  That is after we deal with
the Darwin case, of course.

>> Also, this fails on OS X [1] and I don't really see why:
>>
>> util/vircommand.c:988:1: error: only weak aliases are supported on darwin
>> VIR_MOCKABLE(void,
>> ^
>> ./internal.h:252:60: note: expanded from macro 'VIR_MOCKABLE'
>>      ret name(__VA_ARGS__) __attribute__((noinline, weak, __alias__(#name "Impl"))); \
>
>It appears clang simply doesn't support 'alias' on Darwin.
>
>Docs suggest that we need to use 'weakref(#name  "Impl")' so I'll have
>to test whether that's viable for our usage scenario or not.
>
>Regards,
>Daniel
>--
>|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
>|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
>|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
>
>--
>libvir-list mailing list
>libvir-list@redhat.com
>https://www.redhat.com/mailman/listinfo/libvir-list
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Rewrite the way mockable functions are handled.
Posted by Daniel P. Berrange 6 years, 9 months ago
On Thu, Jul 13, 2017 at 02:33:57PM +0200, Martin Kletzander wrote:
> On Thu, Jul 13, 2017 at 12:25:50PM +0100, Daniel P. Berrange wrote:
> > On Thu, Jul 13, 2017 at 01:14:12PM +0200, Martin Kletzander wrote:
> > > On Wed, Jul 12, 2017 at 05:06:22PM +0100, Daniel P. Berrange wrote:
> > > > Currently any mockable functions are marked with attributes
> > > > noinline, noclone and weak. This prevents the compiler from
> > > > optimizing away the impl of these functions.
> > > >
> > > > It has an unfortunate side effect with the libtool convenience
> > > > libraries, if executables directly link to them. For example
> > > > virlockd, virlogd both link to libvirt_util.la  When this is
> > > > done, the linker does not consider weak symbols as being
> > > > undefined, so it never copies them into the final executable.
> > > >
> > > > In this new approach, we stop annotating the headers entirely.
> > > > Instead we create a weak function alias in the source.
> > > >
> > > >   int fooImpl(void) {
> > > >      ..the real code..
> > > >   }
> > > >
> > > >   int foo(void) __attribute__((noinline, noclone, weak, alias("fooImpl"))
> > > >
> > > > If any functions in the same file call "foo", this prevents the
> > > > optimizer from inlining any part of fooImpl. When linking to the
> > > > libtool convenience static library, we also get all the symbols
> > > > present. Finally the test suite can just directly define a
> > > > 'foo' function in its source, removing the need to use LD_PRELOAD
> > > > (though removal of LD_PRELOADS is left for a future patch).
> > > >
> > > 
> > > What are you using for tag navigation?  With this macro-defined
> > > functions I cannot easily jump to them (the main reason why I don't like
> > > macros defining functions).
> > 
> > Grep & historic knowledge :-)
> > 
> > >                              I would very much prefer if
> > > ATTRIBUTE_MOCKABLE just took a parameter like this:
> > > 
> > > #define ATTRIBUTE_MOCKABLE(func) __attribute__((noinline, noclone, weak, alias(#func "Impl"))
> > > 
> > > (written by hand, don't take mu word for it working out of the box) and
> > > the original function would be left untouched.
> > 
> > Yeah, that is certainly a valid alternative. I was not entirely happy
> > with the results I get here. As long as we don't mind repeating the
> > arg list in both places, your approach is more attractive, despite
> > the duplication.
> > 
> 
> I think we don't if we do:
> 
> #define VIR_MOCKABLE(ret, name) typeof(name ## Impl) name \
>    __attribute__((noinline, weak, __alias__(#name "Impl")));
> 
> or can't this be done for functions?  It worked when I tried it now.

I've never tried typeof in this way, so I guess we can experiment.

> I have one more idea, though.  So that we don't have to double-type the
> actual definition of the Impl function, we can make it static.  What if
> we make *all* functions static and only add weak aliases to those that
> are supposed to be used outside the file?  That is after we deal with
> the Darwin case, of course.

NB, I orignally marked the funtions as static, but clang complains that
they are unused, despite being referenced from an alias annotation.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list