]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
annotate all mocked functions with noinline
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 7 Apr 2017 14:07:49 +0000 (15:07 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 19 Apr 2017 09:51:51 +0000 (10:51 +0100)
CLang's optimizer is more aggressive at inlining functions than
gcc and so will often inline functions that our tests want to
mock-override. This causes the test to fail in bizarre ways.

We don't want to disable inlining completely, but we must at
least prevent inlining of mocked functions. Fortunately there
is a 'noinline' attribute that lets us control this per function.

A syntax check rule is added that parses tests/*mock.c to extract
the list of functions that are mocked (restricted to names starting
with 'vir' prefix). It then checks that src/*.h header file to
ensure it has a 'ATTRIBUTE_NOINLINE' annotation. This should prevent
use from bit-rotting in future.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
21 files changed:
build-aux/mock-noinline.pl [new file with mode: 0644]
cfg.mk
src/internal.h
src/qemu/qemu_capspriv.h
src/rpc/virnetsocket.h
src/util/vircommand.h
src/util/vircrypto.h
src/util/virfile.h
src/util/virhostcpu.h
src/util/virmacaddr.h
src/util/virnetdev.h
src/util/virnetdevip.h
src/util/virnetdevopenvswitch.h
src/util/virnetdevtap.h
src/util/virnuma.h
src/util/virrandom.h
src/util/virscsi.h
src/util/virscsivhost.h
src/util/virtpm.h
src/util/virutil.h
src/util/viruuid.h

diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl
new file mode 100644 (file)
index 0000000..eafe20d
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+
+my %noninlined;
+my %mocked;
+
+# Functions in public header don't get the noinline annotation
+# so whitelist them here
+$noninlined{"virEventAddTimeout"} = 1;
+
+foreach my $arg (@ARGV) {
+    if ($arg =~ /\.h$/) {
+        #print "Scan header $arg\n";
+        &scan_annotations($arg);
+    } elsif ($arg =~ /mock\.c$/) {
+        #print "Scan mock $arg\n";
+        &scan_overrides($arg);
+    }
+}
+
+my $warned = 0;
+foreach my $func (keys %mocked) {
+    next if exists $noninlined{$func};
+
+    $warned++;
+    print STDERR "$func is mocked at $mocked{$func} but missing noinline annotation\n";
+}
+
+exit $warned ? 1 : 0;
+
+
+sub scan_annotations {
+    my $file = shift;
+
+    open FH, $file or die "cannot read $file: $!";
+
+    my $func;
+    while (<FH>) {
+        if (/^\s*(\w+)\(/ || /^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(/) {
+            my $name = $1;
+            if ($name !~ /ATTRIBUTE/) {
+                $func = $name;
+            }
+        } elsif (/^\s*$/) {
+            $func = undef;
+        }
+        if (/ATTRIBUTE_NOINLINE/) {
+            if (defined $func) {
+                $noninlined{$func} = 1;
+            }
+        }
+    }
+
+    close FH
+}
+
+sub scan_overrides {
+    my $file = shift;
+
+    open FH, $file or die "cannot read $file: $!";
+
+    my $func;
+    while (<FH>) {
+        if (/^(\w+)\(/ || /^\w+\s*(?:\*\s*)?(\w+)\(/) {
+            my $name = $1;
+            if ($name =~ /^vir/) {
+                $mocked{$name} = "$file:$.";
+            }
+        }
+    }
+
+    close FH
+}
diff --git a/cfg.mk b/cfg.mk
index 4c2219524e7733a297a95935a9c738a7c59127b6..09548fecd994b00a7198b1672c1a6393ac52b286 100644 (file)
--- a/cfg.mk
+++ b/cfg.mk
@@ -1069,7 +1069,7 @@ _autogen:
 # regenerate HACKING as part of the syntax-check
 ifneq ($(_gl-Makefile),)
 syntax-check: $(top_srcdir)/HACKING spacing-check test-wrap-argv \
-       prohibit-duplicate-header
+       prohibit-duplicate-header mock-noinline
 endif
 
 # Don't include duplicate header in the source (either *.c or *.h)
@@ -1083,6 +1083,10 @@ spacing-check:
          { echo '$(ME): incorrect formatting, see HACKING for rules' 1>&2; \
            exit 1; }
 
+mock-noinline:
+       $(AM_V_GEN)files=`$(VC_LIST) | grep '\.[ch]$$'`; \
+       $(PERL) $(top_srcdir)/build-aux/mock-noinline.pl $$files
+
 test-wrap-argv:
        $(AM_V_GEN)files=`$(VC_LIST) | grep -E '\.(ldargs|args)'`; \
        $(PERL) $(top_srcdir)/tests/test-wrap-argv.pl --check $$files
index d64be93b348a1ff89d52808414db359624d27bb0..b1a05568a3ad64524b2cf566cf56021473d1092b 100644 (file)
 #   endif
 #  endif
 
+/**
+ * ATTRIBUTE_NOINLINE:
+ *
+ * Force compiler not to inline a method. Should be used if
+ * the method need to be overridable by test mocks.
+ */
+#  ifndef ATTRIBUTE_NOINLINE
+#   if __GNUC_PREREQ (4, 0)
+#    define ATTRIBUTE_NOINLINE __attribute__((__noinline__))
+#   else
+#    define ATTRIBUTE_NOINLINE
+#   endif
+#  endif
+
 /**
  * ATTRIBUTE_FMT_PRINTF
  *
 #  ifndef ATTRIBUTE_RETURN_CHECK
 #   define ATTRIBUTE_RETURN_CHECK
 #  endif
+#  ifndef ATTRIBUTE_NOINLINE
+#   define ATTRIBUTE_NOINLINE
+#  endif
 #
 #  ifndef ATTRIBUTE_FALLTHROUGH
 #   define ATTRIBUTE_FALLTHROUGH do {} while(0)
index a7c92fd10b930b91a16dcd23e42108fbe1730d66..94fa75b96016d1f8ffa2f739b7ab1e91e7591f2f 100644 (file)
@@ -95,7 +95,7 @@ virQEMUCapsSetCPUModelInfo(virQEMUCapsPtr qemuCaps,
 virCPUDefPtr
 virQEMUCapsProbeHostCPUForEmulator(virCapsPtr caps,
                                    virQEMUCapsPtr qemuCaps,
-                                   virDomainVirtType type);
+                                   virDomainVirtType type) ATTRIBUTE_NOINLINE;
 
 void
 virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps,
index 1e75ee62b2964e1867641a74fea3cfb5d0660027..de795af9170bda49f195b103b3fa5b2620370e49 100644 (file)
@@ -136,9 +136,11 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
                                 uid_t *uid,
                                 gid_t *gid,
                                 pid_t *pid,
-                                unsigned long long *timestamp);
+                                unsigned long long *timestamp)
+    ATTRIBUTE_NOINLINE;
 int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
-                                  char **context);
+                                  char **context)
+    ATTRIBUTE_NOINLINE;
 
 int virNetSocketSetBlocking(virNetSocketPtr sock,
                             bool blocking);
index 99dcdeb541a7e97f3b922a25a47a93ac09d4729a..e7c2e513bae15651fc29f317049be4686e4063b8 100644 (file)
@@ -58,7 +58,7 @@ enum {
 
 void virCommandPassFD(virCommandPtr cmd,
                       int fd,
-                      unsigned int flags);
+                      unsigned int flags) ATTRIBUTE_NOINLINE;
 
 void virCommandPassListenFDs(virCommandPtr cmd);
 
index 52ba3b3ad0221ddfea569cdd3edb85ef5d8e3298..068602f5dfc435b48dcb43c5eabc070c27c15536 100644 (file)
@@ -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);
+uint8_t *virCryptoGenerateRandom(size_t nbytes) ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_CRYPTO_H__ */
index ba1c57c06a8e6344b0e8baa8ff1965c5880b8d9a..41c25a2b5f4bc36882b9bb01bceed75c8598fa53 100644 (file)
@@ -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);
+bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NOINLINE;
 bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1);
 
 enum {
index e9c22eecc9c93275ce27922a723626a5158672a6..67033de8422bbc7b3ec69ad7891a00e0d1a6c2c0 100644 (file)
@@ -38,7 +38,7 @@ bool virHostCPUHasBitmap(void);
 virBitmapPtr virHostCPUGetPresentBitmap(void);
 virBitmapPtr virHostCPUGetOnlineBitmap(void);
 int virHostCPUGetCount(void);
-int virHostCPUGetThreadsPerSubcore(virArch arch);
+int virHostCPUGetThreadsPerSubcore(virArch arch) ATTRIBUTE_NOINLINE;
 
 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);
+int virHostCPUGetKVMMaxVCPUs(void) ATTRIBUTE_NOINLINE;
 
 int virHostCPUStatsAssign(virNodeCPUStatsPtr param,
                           const char *name,
index ae26867d4d333bbb712003e9c197231e2cec44e7..f4f5e2ce117288f7b5ee5f72be92dc646e786214 100644 (file)
@@ -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);
+                        virMacAddrPtr addr) ATTRIBUTE_NOINLINE;
 int virMacAddrParse(const char* str,
                     virMacAddrPtr addr) ATTRIBUTE_RETURN_CHECK;
 int virMacAddrParseHex(const char* str,
index 437a776257b6ce1de53c3bf9ee737c25d7166569..12a31236c546cd8c551272148bac8f012f2c77bb 100644 (file)
@@ -121,7 +121,7 @@ int virNetDevExists(const char *brname)
 
 int virNetDevSetOnline(const char *ifname,
                        bool online)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 int virNetDevGetOnline(const char *ifname,
                       bool *online)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
@@ -129,7 +129,7 @@ int virNetDevGetOnline(const char *ifname,
 
 int virNetDevSetMAC(const char *ifname,
                     const virMacAddr *macaddr)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 int virNetDevGetMAC(const char *ifname,
                     virMacAddrPtr macaddr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
@@ -263,7 +263,8 @@ 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_RETURN_CHECK ATTRIBUTE_NOINLINE;
 
-int virNetDevRunEthernetScript(const char *ifname, const char *script);
+int virNetDevRunEthernetScript(const char *ifname, const char *script)
+    ATTRIBUTE_NOINLINE;
 #endif /* __VIR_NETDEV_H__ */
index cc466ca259692986358153e516dc2d84595ced4d..6b509ea445ac204782ce50bf505a156474e0020b 100644 (file)
@@ -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_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 int virNetDevIPRouteAdd(const char *ifname,
                         virSocketAddrPtr addr,
                         unsigned int prefix,
index 7380a2d84bc35f0c329440e839a7b0912f218dc7..51bb1dd006b9e2e6328925b2f2bb5131136b3ccf 100644 (file)
@@ -59,6 +59,6 @@ int virNetDevOpenvswitchInterfaceStats(const char *ifname,
 
 int virNetDevOpenvswitchGetVhostuserIfname(const char *path,
                                            char **ifname)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
index 6bb3b8891c2165627e3ffa79792f7c2920bdc87c..311f0698b155dea401c82d244dfa1ec0a7f9846c 100644 (file)
@@ -38,7 +38,7 @@ int virNetDevTapCreate(char **ifname,
                        int *tapfd,
                        size_t tapfdSize,
                        unsigned int flags)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 
 int virNetDevTapDelete(const char *ifname,
                        const char *tunpath)
@@ -48,7 +48,7 @@ int virNetDevTapGetName(int tapfd, char **ifname)
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 
 char* virNetDevTapGetRealDeviceName(char *ifname)
-      ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+      ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
 
 typedef enum {
    VIR_NETDEV_TAP_CREATE_NONE = 0,
@@ -87,7 +87,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_RETURN_CHECK ATTRIBUTE_NOINLINE;
 
 int virNetDevTapInterfaceStats(const char *ifname,
                                virDomainInterfaceStatsPtr stats)
index f3eef324a4978fb89420c74bdab22f12e825ad58..e4e1fd0b9755989d590312096a72f0837e3ce5e7 100644 (file)
@@ -34,20 +34,20 @@ int virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
                              virBitmapPtr nodeset);
 
 virBitmapPtr virNumaGetHostMemoryNodeset(void);
-bool virNumaNodesetIsAvailable(virBitmapPtr nodeset);
-bool virNumaIsAvailable(void);
-int virNumaGetMaxNode(void);
-bool virNumaNodeIsAvailable(int node);
+bool virNumaNodesetIsAvailable(virBitmapPtr nodeset) ATTRIBUTE_NOINLINE;
+bool virNumaIsAvailable(void) ATTRIBUTE_NOINLINE;
+int virNumaGetMaxNode(void) ATTRIBUTE_NOINLINE;
+bool virNumaNodeIsAvailable(int node) ATTRIBUTE_NOINLINE;
 int virNumaGetDistances(int node,
                         int **distances,
-                        int *ndistances);
+                        int *ndistances) ATTRIBUTE_NOINLINE;
 int virNumaGetNodeMemory(int node,
                          unsigned long long *memsize,
-                         unsigned long long *memfree);
+                         unsigned long long *memfree) ATTRIBUTE_NOINLINE;
 
 unsigned int virNumaGetMaxCPUs(void);
 
-int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus);
+int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus) ATTRIBUTE_NOINLINE;
 
 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_NONNULL(5) ATTRIBUTE_NOINLINE;
 int virNumaSetPagePoolSize(int node,
                            unsigned int page_size,
                            unsigned long long page_count,
index f457d2de66cd2ed56917d61b8157ef784ce2ce47..7a984ee7b09eb3705f63c4eff256ccadeaa9f348 100644 (file)
 
 # include "internal.h"
 
-uint64_t virRandomBits(int nbits);
+uint64_t virRandomBits(int nbits) ATTRIBUTE_NOINLINE;
 double virRandom(void);
 uint32_t virRandomInt(uint32_t max);
 int virRandomBytes(unsigned char *buf, size_t buflen)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
-int virRandomGenerateWWN(char **wwn, const char *virt_type);
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NOINLINE;
+int virRandomGenerateWWN(char **wwn, const char *virt_type) ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_RANDOM_H__ */
index 7d88d4e708efec97c81de91f798f1824a9478d80..9f8b3ecf1e6409f941b9d2ff07e8d318ee3f5c75 100644 (file)
@@ -37,7 +37,7 @@ char *virSCSIDeviceGetSgName(const char *sysfs_prefix,
                              const char *adapter,
                              unsigned int bus,
                              unsigned int target,
-                             unsigned long long unit);
+                             unsigned long long unit) ATTRIBUTE_NOINLINE;
 char *virSCSIDeviceGetDevName(const char *sysfs_prefix,
                               const char *adapter,
                               unsigned int bus,
index 6018b835e9d90d05bc75e763c45153a416f6abef..21887ddbd5d49500b4c427bed19c18e58872edd2 100644 (file)
@@ -61,6 +61,6 @@ void virSCSIVHostDeviceGetUsedBy(virSCSIVHostDevicePtr dev,
                                  const char **drv_name,
                                  const char **dom_name);
 void virSCSIVHostDeviceFree(virSCSIVHostDevicePtr dev);
-int virSCSIVHostOpenVhostSCSI(int *vhostfd);
+int virSCSIVHostOpenVhostSCSI(int *vhostfd) ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_SCSIHOST_H__ */
index fe71307a1e0f84c1fe027537d874a520b7636702..b21fc0532f8df09b37073b15462bab212d4d4d41 100644 (file)
@@ -22,6 +22,6 @@
 #ifndef __VIR_TPM_H__
 # define __VIR_TPM_H__
 
-char *virTPMCreateCancelPath(const char *devpath);
+char *virTPMCreateCancelPath(const char *devpath) ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_TPM_H__ */
index e097b77212fca3b0e8154091eef239453cdddee4..86e9051225ba7ef4a2df6ba47ea49d3361e12d7d 100644 (file)
@@ -142,8 +142,8 @@ char *virGetUserConfigDirectory(void);
 char *virGetUserCacheDirectory(void);
 char *virGetUserRuntimeDirectory(void);
 char *virGetUserShell(uid_t uid);
-char *virGetUserName(uid_t uid);
-char *virGetGroupName(gid_t gid);
+char *virGetUserName(uid_t uid) ATTRIBUTE_NOINLINE;
+char *virGetGroupName(gid_t gid) ATTRIBUTE_NOINLINE;
 int virGetGroupList(uid_t uid, gid_t group, gid_t **groups)
     ATTRIBUTE_NONNULL(3);
 int virGetUserID(const char *name,
@@ -204,12 +204,12 @@ verify((int)VIR_TRISTATE_BOOL_ABSENT == (int)VIR_TRISTATE_SWITCH_ABSENT);
 
 unsigned int virGetListenFDs(void);
 
-long virGetSystemPageSize(void);
-long virGetSystemPageSizeKB(void);
+long virGetSystemPageSize(void) ATTRIBUTE_NOINLINE;
+long virGetSystemPageSizeKB(void) ATTRIBUTE_NOINLINE;
 
 unsigned long long virMemoryLimitTruncate(unsigned long long value);
 bool virMemoryLimitIsSet(unsigned long long value);
-unsigned long long virMemoryMaxValue(bool ulong);
+unsigned long long virMemoryMaxValue(bool ulong) ATTRIBUTE_NOINLINE;
 
 /**
  * VIR_ASSIGN_IS_OVERFLOW:
index 5790a173648e4f825aef2f41126bc1ef99acda3c..1d67e9ee57ea4276ea2806a6ca59549827c7e9b8 100644 (file)
@@ -49,7 +49,7 @@ int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1);
 
 int virUUIDIsValid(unsigned char *uuid);
 
-int virUUIDGenerate(unsigned char *uuid);
+int virUUIDGenerate(unsigned char *uuid) ATTRIBUTE_NOINLINE;
 
 int virUUIDParse(const char *uuidstr,
                  unsigned char *uuid)