]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
internal: Introduce ATTRIBUTE_MOCKABLE
authorMichal Privoznik <mprivozn@redhat.com>
Mon, 28 Apr 2025 08:49:57 +0000 (10:49 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Fri, 2 May 2025 12:31:19 +0000 (14:31 +0200)
Currently, if we want to mock a function the noinline attribute
is appended after the function (via G_NO_INLINE macro). This used
to work for non pure functions. But there are some trivial
functions (for instance virQEMUCapsProbeHVF()) that are pure,
i.e. have no side effect, and while their call from other parts
of the code is not optimized out, their call from within the same
compilation unit (qemu_capabilities.c) is optimized out.

This is because inlining and semantic interposition are two
different things. Even GCC's documentation for noinline attribute
[1] states that clearly:

  This function attribute prevents a function from being
  considered for inlining. It also disables some other
  interprocedural optimizations; it’s preferable to use the more
  comprehensive noipa attribute instead if that is your goal.

  Even if a function is declared with the noinline attribute,
  there are optimizations other than inlining that can cause
  calls to be optimized away if it does not have side effects,
  although the function call is live.

Unfortunately, despite attempts [2] Clang still does not support
the attribute and thus we have to rely on noinline +
-fsemantic-interposition combo.

1: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noinline-function-attribute
2: https://reviews.llvm.org/D101011

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
docs/coding-style.rst
scripts/cocci-macro-file.h
src/internal.h

index fe5fe9a906e0354b54fb8afbf60e9531f3fc777a..a4934ef333631c00ced0b4db9992ce11972af569 100644 (file)
@@ -633,7 +633,7 @@ analysis tools understand the code better:
 ``G_GNUC_FALLTHROUGH``
    allow code reuse by multiple switch cases
 
-``G_NO_INLINE``
+``ATTRIBUTE_MOCKABLE``
    the function is mocked in the test suite
 
 ``G_GNUC_NORETURN``
index c3112663d1f7efb9d1358d047a24beb6c21d00f7..4f70c6b4ccc50392570e437ae5e90fe20dcc3e52 100644 (file)
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#define ATTRIBUTE_MOCKABLE
 #define ATTRIBUTE_NONNULL(x)
 #define ATTRIBUTE_PACKED
 
index 20aa9b1d418982fdffddd1da9864c312d33e8c5e..bd62a25ef893316e69a5f366cc83df42923d6496 100644 (file)
 # endif
 #endif
 
+/**
+ *
+ * ATTRIBUTE_MOCKABLE
+ *
+ * Force compiler to disable interprocedural optimizations between the
+ * function with this attribute and its callers. On compilers that
+ * support it (gcc), this expands to noipa attribute which implies
+ * noinline attribute and some others and allows us to mock functions
+ * even if they are pure.
+ *
+ * On compilers which don't support the noipa attribute (clang) this
+ * expands to noinline attribute which in combination with the
+ * -fsemantic-interposition option does roughly the same.
+ */
+#ifndef ATTRIBUTE_MOCKABLE
+# if defined(__has_attribute) && __has_attribute(noipa)
+#  define ATTRIBUTE_MOCKABLE __attribute__((noipa))
+# else
+#  define ATTRIBUTE_MOCKABLE G_NO_INLINE
+# endif
+#endif
+
 #define VIR_WARNINGS_NO_CAST_ALIGN \
     _Pragma ("GCC diagnostic push") \
     _Pragma ("GCC diagnostic ignored \"-Wcast-align\"")