The clang compiler behaves very aggressively when optimizing some
functions. So much so that it in fact breaks our mocking (or any
LD preloading for that matter). For instance, for the following
code:
int X(void) G_NO_INLINE;
int Y(void);
int X(void)
{
return -1;
}
int Y(void)
{
if (X() < 0)
return -1;
return 42;
}
the following assembler is generated:
0000000000118090 <X>:
118090: b8 ff ff ff ff mov $0xffffffff,%eax
118095: c3 ret
00000000001180a0 <Y>:
1180a0: b8 ff ff ff ff mov $0xffffffff,%eax
1180a5: c3 ret
It's clear that Y() does not even attempt to call X(). Therefore,
even if we provided an alternative implementation (or anybody
else for that matter), it is not even called.
Note, this happens only with optimizations enabled, i.e. -O1 and
bigger. For -O0 clang does the right thing. Fortunately, it
offers a way to disable optimizations on a per-function basis.
From our example, if X() and Y() are written like this:
int __attribute__((optnone)) X(void)
{
return -1;
}
int __attribute__((optnone)) Y(void)
{
if (X() < 0)
return -1;
return 42;
}
then the expected happen, regardless of optimization setting.
Therefore, introduce VIR_OPTNONE macro which sets this attribute
when building with clang.
Fortunately, other compilers realize that they can not do this
optimization for non-static functions and thus VIR_OPTNONE can be
empty for them.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/internal.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/internal.h b/src/internal.h
index 9dc34a0bf5..cf6f314648 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -552,3 +552,23 @@ enum {
# define fprintf(fh, ...) g_fprintf(fh, __VA_ARGS__)
#endif /* VIR_NO_GLIB_STDIO */
+
+/* Ideally, we would not need this. But, we want to work with
+ * broken compilers. Use this to disable optimizations for a
+ * function, like this:
+ *
+ * int VIR_OPTNONE
+ * virMyFunction(int arg)
+ * {
+ * ...
+ * }
+ *
+ * Do NOT use in the header file as it has no effect there. This
+ * is intended to be used for functions that (might) call or be
+ * called from mocked function.
+ */
+#if defined(__clang__)
+# define VIR_OPTNONE __attribute__((optnone))
+#else
+# define VIR_OPTNONE
+#endif
--
2.39.2