[PATCH 05/15] tests: Fix mocking of open()

Michal Privoznik via Devel posted 15 patches 2 months, 4 weeks ago
[PATCH 05/15] tests: Fix mocking of open()
Posted by Michal Privoznik via Devel 2 months, 4 weeks ago
From: Michal Privoznik <mprivozn@redhat.com>

In some cases (well, majority), open() is either rewritten to
open64(), either by plain '#define open open64') or at assembly
level (using __REDIRECT macro). See <fcntl.h> for more info.

This didn't really matter to us, because we do not chain load two
mocks that would need to reimplement open() at the same time. But
this is soon going to change.

The problem is, that VIR_MOCK_REAL_INIT(open) glances over
aforementioned rewrite and initializes real_open pointer to
open() from the standard C library. But it needs to point to
open() (well, open64()) from the next mock on the list.

Therefore, init real_open to open64().

But of course, this is all glibc specific and for example musl
does the oposite (#define open64 open).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
---
 tests/nssmock.c          | 4 ++++
 tests/qemusecuritymock.c | 4 ++++
 tests/vircgroupmock.c    | 4 ++++
 tests/virfilewrapper.c   | 4 ++++
 tests/virpcimock.c       | 4 ++++
 tests/virtestmock.c      | 4 ++++
 tests/virusbmock.c       | 4 ++++
 7 files changed, 28 insertions(+)

diff --git a/tests/nssmock.c b/tests/nssmock.c
index 3493119f3b..d47fe7b10f 100644
--- a/tests/nssmock.c
+++ b/tests/nssmock.c
@@ -46,7 +46,11 @@ init_syms(void)
     if (real_open)
         return;
 
+# if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+# else
     VIR_MOCK_REAL_INIT(open);
+# endif
 # if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 # endif
diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c
index 2dfd6c33a0..d5c711b5d7 100644
--- a/tests/qemusecuritymock.c
+++ b/tests/qemusecuritymock.c
@@ -115,7 +115,11 @@ init_syms(void)
         return;
 
     VIR_MOCK_REAL_INIT(chown);
+#if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+#else
     VIR_MOCK_REAL_INIT(open);
+#endif
 #if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 #endif
diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c
index d922f30f34..a5c18bd7b0 100644
--- a/tests/vircgroupmock.c
+++ b/tests/vircgroupmock.c
@@ -304,7 +304,11 @@ static void init_syms(void)
     VIR_MOCK_REAL_INIT(fopen);
     VIR_MOCK_REAL_INIT(access);
     VIR_MOCK_REAL_INIT(mkdir);
+# if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+# else
     VIR_MOCK_REAL_INIT(open);
+# endif
 # if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 # endif
diff --git a/tests/virfilewrapper.c b/tests/virfilewrapper.c
index 908f7142c2..3bccca9c11 100644
--- a/tests/virfilewrapper.c
+++ b/tests/virfilewrapper.c
@@ -56,7 +56,11 @@ static void init_syms(void)
     VIR_MOCK_REAL_INIT(fopen);
     VIR_MOCK_REAL_INIT(access);
     VIR_MOCK_REAL_INIT(mkdir);
+# if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+# else
     VIR_MOCK_REAL_INIT(open);
+# endif
 # if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 # endif
diff --git a/tests/virpcimock.c b/tests/virpcimock.c
index 4eff6d70e3..ca345f37a3 100644
--- a/tests/virpcimock.c
+++ b/tests/virpcimock.c
@@ -945,7 +945,11 @@ init_syms(void)
         return;
 
     VIR_MOCK_REAL_INIT(access);
+# if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+# else
     VIR_MOCK_REAL_INIT(open);
+# endif
 # if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 # endif /* WITH___OPEN_2 */
diff --git a/tests/virtestmock.c b/tests/virtestmock.c
index 5b25b380e5..a5c3b29f39 100644
--- a/tests/virtestmock.c
+++ b/tests/virtestmock.c
@@ -46,7 +46,11 @@ static void init_syms(void)
     if (real_open)
         return;
 
+#if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+#else
     VIR_MOCK_REAL_INIT(open);
+#endif
 #if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 #endif
diff --git a/tests/virusbmock.c b/tests/virusbmock.c
index e148296b7c..c23bed4528 100644
--- a/tests/virusbmock.c
+++ b/tests/virusbmock.c
@@ -40,7 +40,11 @@ static void init_syms(void)
     if (real_open)
         return;
 
+#if defined(__GLIBC__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+    VIR_MOCK_REAL_INIT_ALIASED(open, "open64");
+#else
     VIR_MOCK_REAL_INIT(open);
+#endif
 #if WITH___OPEN_2
     VIR_MOCK_REAL_INIT(__open_2);
 #endif
-- 
2.49.0
Re: [PATCH 05/15] tests: Fix mocking of open()
Posted by Ján Tomko via Devel 2 months, 1 week ago
On a Thursday in 2025, Michal Privoznik via Devel wrote:
>From: Michal Privoznik <mprivozn@redhat.com>
>
>In some cases (well, majority), open() is either rewritten to
>open64(), either by plain '#define open open64') or at assembly
>level (using __REDIRECT macro). See <fcntl.h> for more info.
>
>This didn't really matter to us, because we do not chain load two
>mocks that would need to reimplement open() at the same time. But
>this is soon going to change.
>
>The problem is, that VIR_MOCK_REAL_INIT(open) glances over
>aforementioned rewrite and initializes real_open pointer to
>open() from the standard C library. But it needs to point to
>open() (well, open64()) from the next mock on the list.
>
>Therefore, init real_open to open64().

I cannot find it in the git history. Did we use to mock open64
separately? Or was that one of the other open's glibc might expand it
to?

Jano

>
>But of course, this is all glibc specific and for example musl
>does the oposite (#define open64 open).
>
>Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
>---
> tests/nssmock.c          | 4 ++++
> tests/qemusecuritymock.c | 4 ++++
> tests/vircgroupmock.c    | 4 ++++
> tests/virfilewrapper.c   | 4 ++++
> tests/virpcimock.c       | 4 ++++
> tests/virtestmock.c      | 4 ++++
> tests/virusbmock.c       | 4 ++++
> 7 files changed, 28 insertions(+)
>
Re: [PATCH 05/15] tests: Fix mocking of open()
Posted by Michal Prívozník via Devel 2 months, 1 week ago
On 7/2/25 12:23, Ján Tomko wrote:
> On a Thursday in 2025, Michal Privoznik via Devel wrote:
>> From: Michal Privoznik <mprivozn@redhat.com>
>>
>> In some cases (well, majority), open() is either rewritten to
>> open64(), either by plain '#define open open64') or at assembly
>> level (using __REDIRECT macro). See <fcntl.h> for more info.
>>
>> This didn't really matter to us, because we do not chain load two
>> mocks that would need to reimplement open() at the same time. But
>> this is soon going to change.
>>
>> The problem is, that VIR_MOCK_REAL_INIT(open) glances over
>> aforementioned rewrite and initializes real_open pointer to
>> open() from the standard C library. But it needs to point to
>> open() (well, open64()) from the next mock on the list.
>>
>> Therefore, init real_open to open64().
> 
> I cannot find it in the git history. Did we use to mock open64
> separately? Or was that one of the other open's glibc might expand it
> to?
> 

I don't remember us ever caring about this. As far as I remember we
initially mocked just open(). Then as of

commit b7e6513a018a897f6ac3f800eae14ff5be6f43f2
    tests: mock __open_2()

we mock __open_2() too, because under some circumstances open() might be
aliased to __open_2(). But that's slightly tangent to the problem I'm
fixing here.

Our VIR_MOCK_REAL_INIT() macro basically does (when expanded):

  real_open = dlsym(RTLD_NEXT, "open");

but combined with fcntl.h header, which has:

  #define open open64

our open() in mocks becomes:

int
open64(...)
{
  ...
  return reeal_open(...);
}


dlsym() succeeds because libc has the "open" symbol, but if we want to
chain mocks then we need to look up "open64" symbol.

Michal