GLibC has a really complicated way of dealing with the 'stat' function
historically, which means our mocks in turn have to look at four
different possible functions to replace, stat, stat64, __xstat,
__xstat64.
In Fedora 33 and earlier:
- libvirt.so links to __xstat64
- libc.so library exports stat, stat64, __xstat, __xstat64
- sys/stat.h header exposes stat and __xstat
In Fedora 34 rawhide:
- libvirt.so links to stat64
- libc.so library exports stat, stat64, __xstat, __xstat64
- sys/stat.h header exposes stat
Historically we only looked at the exported symbols from libc.so to
decide which to mock.
In F34 though we must not consider __xstat / __xstat64 though because
they only existance for binary compatibility. Newly built binaries
won't reference them.
Thus we must introduce a header file check into our logic for deciding
which symbol to mock. We must ignore the __xstat / __xstat64 symbols
if they don't appear in the sys/stat.h header, even if they appear
in libc.so
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
Validated with this pipeline:
https://gitlab.com/berrange/libvirt/-/pipelines/209361200
meson.build | 28 ++++++++++++-----
tests/virmockstathelpers.c | 62 ++++++++++++++++++++++----------------
2 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/meson.build b/meson.build
index c3ba34bbe0..365c16d167 100644
--- a/meson.build
+++ b/meson.build
@@ -636,10 +636,6 @@ libvirt_export_dynamic = cc.first_supported_link_argument([
# check availability of various common functions (non-fatal if missing)
functions = [
- '__lxstat',
- '__lxstat64',
- '__xstat',
- '__xstat64',
'elf_aux_info',
'fallocate',
'getauxval',
@@ -653,8 +649,6 @@ functions = [
'getuid',
'getutxid',
'if_indextoname',
- 'lstat',
- 'lstat64',
'mmap',
'newlocale',
'pipe2',
@@ -666,12 +660,23 @@ functions = [
'setgroups',
'setns',
'setrlimit',
- 'stat',
- 'stat64',
'symlink',
'sysctlbyname',
]
+stat_functions = [
+ '__lxstat',
+ '__lxstat64',
+ '__xstat',
+ '__xstat64',
+ 'lstat',
+ 'lstat64',
+ 'stat',
+ 'stat64',
+]
+
+functions += stat_functions
+
foreach function : functions
if cc.has_function(function)
conf.set('WITH_@0(a)'.format(function.to_upper()), 1)
@@ -679,6 +684,13 @@ foreach function : functions
endforeach
+foreach function : stat_functions
+ if cc.has_header_symbol('sys/stat.h', function)
+ conf.set('WITH_@0(a)_DECL'.format(function.to_upper()), 1)
+ endif
+endforeach
+
+
# various header checks
headers = [
diff --git a/tests/virmockstathelpers.c b/tests/virmockstathelpers.c
index 5c9759551d..3bd2437ffe 100644
--- a/tests/virmockstathelpers.c
+++ b/tests/virmockstathelpers.c
@@ -67,39 +67,49 @@
* - If __xstat & __xstat64 exist, then stat & stat64 will not exist
* as symbols in the library, so the latter should not be mocked.
*
+ * - If __xstat exists in the library, but not the header than it
+ * it is just there for binary back compat and should not be
+ * mocked
+ *
* The same all applies to lstat()
*/
+#if !defined(WITH___XSTAT_DECL)
+# if defined(WITH_STAT)
+# if !defined(WITH___XSTAT) && !defined(WITH_STAT64) || defined(__APPLE__)
+# define MOCK_STAT
+# endif
+# endif
+# if defined(WITH_STAT64)
+# define MOCK_STAT64
+# endif
+#else /* WITH___XSTAT_DECL */
+# if defined(WITH___XSTAT) && !defined(WITH___XSTAT64)
+# define MOCK___XSTAT
+# endif
+# if defined(WITH___XSTAT64)
+# define MOCK___XSTAT64
+# endif
+#endif /* WITH___XSTAT_DECL */
-#if defined(WITH_STAT)
-# if !defined(WITH___XSTAT) && !defined(WITH_STAT64) || defined(__APPLE__)
-# define MOCK_STAT
+#if !defined(WITH___LXSTAT_DECL)
+# if defined(WITH_LSTAT)
+# if !defined(WITH___LXSTAT) && !defined(WITH_LSTAT64) || defined(__APPLE__)
+# define MOCK_LSTAT
+# endif
# endif
-#endif
-#if defined(WITH_STAT64) && !defined(WITH___XSTAT64)
-# define MOCK_STAT64
-#endif
-#if defined(WITH___XSTAT) && !defined(WITH___XSTAT64)
-# define MOCK___XSTAT
-#endif
-#if defined(WITH___XSTAT64)
-# define MOCK___XSTAT64
-#endif
-#if defined(WITH_LSTAT)
-# if !defined(WITH___LXSTAT) && !defined(WITH_LSTAT64) || defined(__APPLE__)
-# define MOCK_LSTAT
+# if defined(WITH_LSTAT64)
+# define MOCK_LSTAT64
# endif
-#endif
-#if defined(WITH_LSTAT64) && !defined(WITH___LXSTAT64)
-# define MOCK_LSTAT64
-#endif
-#if defined(WITH___LXSTAT) && !defined(WITH___LXSTAT64)
-# define MOCK___LXSTAT
-#endif
-#if defined(WITH___LXSTAT64)
-# define MOCK___LXSTAT64
-#endif
+#else /* WITH___LXSTAT_DECL */
+# if defined(WITH___LXSTAT) && !defined(WITH___LXSTAT64)
+# define MOCK___LXSTAT
+# endif
+# if defined(WITH___LXSTAT64)
+# define MOCK___LXSTAT64
+# endif
+#endif /* WITH___LXSTAT_DECL */
#ifdef MOCK_STAT
static int (*real_stat)(const char *path, struct stat *sb);
--
2.28.0