* [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
@ 2025-08-05 17:51 Zi Yan
2025-08-05 18:38 ` Jann Horn
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Zi Yan @ 2025-08-05 17:51 UTC (permalink / raw)
To: wang lian, Andrew Morton, linux-mm
Cc: Lorenzo Stoakes, David Hildenbrand, Wei Yang, Christian Brauner,
Jann Horn, Kairui Song, Liam Howlett, Mark Brown, SeongJae Park,
Shuah Khan, Vlastimil Babka, linux-kernel, linux-kselftest,
Zi Yan
FORCE_READ() converts input value x to its pointer type then reads from
address x. This is wrong. If x is a non-pointer, it would be caught it
easily. But all FORCE_READ() callers are trying to read from a pointer and
FORCE_READ() basically reads a pointer to a pointer instead of the original
typed pointer. Almost no access violation was found, except the one from
split_huge_page_test.
Fix it by implementing a simplified READ_ONCE() instead.
Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
FORCE_READ() comes from commit 876320d71f51 ("selftests/mm: add self tests for
guard page feature"). I will a separate patch to stable tree.
tools/testing/selftests/mm/cow.c | 4 ++--
tools/testing/selftests/mm/guard-regions.c | 2 +-
tools/testing/selftests/mm/hugetlb-madvise.c | 4 +++-
tools/testing/selftests/mm/migration.c | 2 +-
tools/testing/selftests/mm/pagemap_ioctl.c | 2 +-
tools/testing/selftests/mm/split_huge_page_test.c | 7 +++++--
tools/testing/selftests/mm/vm_util.h | 2 +-
7 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c
index d30625c18259..c744c603d688 100644
--- a/tools/testing/selftests/mm/cow.c
+++ b/tools/testing/selftests/mm/cow.c
@@ -1554,8 +1554,8 @@ static void run_with_zeropage(non_anon_test_fn fn, const char *desc)
}
/* Read from the page to populate the shared zeropage. */
- FORCE_READ(mem);
- FORCE_READ(smem);
+ FORCE_READ(*mem);
+ FORCE_READ(*smem);
fn(mem, smem, pagesize);
munmap:
diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c
index b0d42eb04e3a..8dd81c0a4a5a 100644
--- a/tools/testing/selftests/mm/guard-regions.c
+++ b/tools/testing/selftests/mm/guard-regions.c
@@ -145,7 +145,7 @@ static bool try_access_buf(char *ptr, bool write)
if (write)
*ptr = 'x';
else
- FORCE_READ(ptr);
+ FORCE_READ(*ptr);
}
signal_jump_set = false;
diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c
index 1afe14b9dc0c..c5940c0595be 100644
--- a/tools/testing/selftests/mm/hugetlb-madvise.c
+++ b/tools/testing/selftests/mm/hugetlb-madvise.c
@@ -50,8 +50,10 @@ void read_fault_pages(void *addr, unsigned long nr_pages)
unsigned long i;
for (i = 0; i < nr_pages; i++) {
+ unsigned long *addr2 =
+ ((unsigned long *)(addr + (i * huge_page_size)));
/* Prevent the compiler from optimizing out the entire loop: */
- FORCE_READ(((unsigned long *)(addr + (i * huge_page_size))));
+ FORCE_READ(*addr2);
}
}
diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c
index c5a73617796a..ea945eebec2f 100644
--- a/tools/testing/selftests/mm/migration.c
+++ b/tools/testing/selftests/mm/migration.c
@@ -110,7 +110,7 @@ void *access_mem(void *ptr)
* the memory access actually happens and prevents the compiler
* from optimizing away this entire loop.
*/
- FORCE_READ((uint64_t *)ptr);
+ FORCE_READ(*(uint64_t *)ptr);
}
return NULL;
diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
index 0d4209eef0c3..e6face7c0166 100644
--- a/tools/testing/selftests/mm/pagemap_ioctl.c
+++ b/tools/testing/selftests/mm/pagemap_ioctl.c
@@ -1525,7 +1525,7 @@ void zeropfn_tests(void)
ret = madvise(mem, hpage_size, MADV_HUGEPAGE);
if (!ret) {
- FORCE_READ(mem);
+ FORCE_READ(*mem);
ret = pagemap_ioctl(mem, hpage_size, &vec, 1, 0,
0, PAGE_IS_PFNZERO, 0, 0, PAGE_IS_PFNZERO);
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
index 718daceb5282..3c761228e451 100644
--- a/tools/testing/selftests/mm/split_huge_page_test.c
+++ b/tools/testing/selftests/mm/split_huge_page_test.c
@@ -440,8 +440,11 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd,
}
madvise(*addr, fd_size, MADV_HUGEPAGE);
- for (size_t i = 0; i < fd_size; i++)
- FORCE_READ((*addr + i));
+ for (size_t i = 0; i < fd_size; i++) {
+ char *addr2 = *addr + i;
+
+ FORCE_READ(*addr2);
+ }
if (!check_huge_file(*addr, fd_size / pmd_pagesize, pmd_pagesize)) {
ksft_print_msg("No large pagecache folio generated, please provide a filesystem supporting large folio\n");
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index c20298ae98ea..b55d1809debc 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -23,7 +23,7 @@
* anything with it in order to trigger a read page fault. We therefore must use
* volatile to stop the compiler from optimising this away.
*/
-#define FORCE_READ(x) (*(volatile typeof(x) *)x)
+#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
extern unsigned int __page_size;
extern unsigned int __page_shift;
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 17:51 [PATCH] selftests/mm: fix FORCE_READ to read input value correctly Zi Yan
@ 2025-08-05 18:38 ` Jann Horn
2025-08-05 18:48 ` Zi Yan
2025-08-05 19:00 ` Lorenzo Stoakes
` (2 subsequent siblings)
3 siblings, 1 reply; 12+ messages in thread
From: Jann Horn @ 2025-08-05 18:38 UTC (permalink / raw)
To: Zi Yan
Cc: wang lian, Andrew Morton, linux-mm, Lorenzo Stoakes,
David Hildenbrand, Wei Yang, Christian Brauner, Kairui Song,
Liam Howlett, Mark Brown, SeongJae Park, Shuah Khan,
Vlastimil Babka, linux-kernel, linux-kselftest
On Tue, Aug 5, 2025 at 7:51 PM Zi Yan <ziy@nvidia.com> wrote:
> FORCE_READ() converts input value x to its pointer type then reads from
> address x. This is wrong. If x is a non-pointer, it would be caught it
> easily. But all FORCE_READ() callers are trying to read from a pointer and
> FORCE_READ() basically reads a pointer to a pointer instead of the original
> typed pointer. Almost no access violation was found, except the one from
> split_huge_page_test.
[...]
> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> index c20298ae98ea..b55d1809debc 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -23,7 +23,7 @@
> * anything with it in order to trigger a read page fault. We therefore must use
> * volatile to stop the compiler from optimising this away.
> */
> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
So is the problem with the old code basically that it should have been
something like
#define FORCE_READ(x) (*(volatile typeof(*(x)) *)(x))
to actually cast the normal pointer to a volatile pointer?
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 18:38 ` Jann Horn
@ 2025-08-05 18:48 ` Zi Yan
2025-08-05 18:56 ` Lorenzo Stoakes
0 siblings, 1 reply; 12+ messages in thread
From: Zi Yan @ 2025-08-05 18:48 UTC (permalink / raw)
To: Jann Horn
Cc: wang lian, Andrew Morton, linux-mm, Lorenzo Stoakes,
David Hildenbrand, Wei Yang, Christian Brauner, Kairui Song,
Liam Howlett, Mark Brown, SeongJae Park, Shuah Khan,
Vlastimil Babka, linux-kernel, linux-kselftest
On 5 Aug 2025, at 14:38, Jann Horn wrote:
> On Tue, Aug 5, 2025 at 7:51 PM Zi Yan <ziy@nvidia.com> wrote:
>> FORCE_READ() converts input value x to its pointer type then reads from
>> address x. This is wrong. If x is a non-pointer, it would be caught it
>> easily. But all FORCE_READ() callers are trying to read from a pointer and
>> FORCE_READ() basically reads a pointer to a pointer instead of the original
>> typed pointer. Almost no access violation was found, except the one from
>> split_huge_page_test.
> [...]
>> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
>> index c20298ae98ea..b55d1809debc 100644
>> --- a/tools/testing/selftests/mm/vm_util.h
>> +++ b/tools/testing/selftests/mm/vm_util.h
>> @@ -23,7 +23,7 @@
>> * anything with it in order to trigger a read page fault. We therefore must use
>> * volatile to stop the compiler from optimising this away.
>> */
>> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
>> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
>
> So is the problem with the old code basically that it should have been
> something like
>
> #define FORCE_READ(x) (*(volatile typeof(*(x)) *)(x))
>
> to actually cast the normal pointer to a volatile pointer?
Yeah. That works too. I would rename it to FORCE_READ_PTR to avoid
misuse. :)
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 18:48 ` Zi Yan
@ 2025-08-05 18:56 ` Lorenzo Stoakes
0 siblings, 0 replies; 12+ messages in thread
From: Lorenzo Stoakes @ 2025-08-05 18:56 UTC (permalink / raw)
To: Zi Yan
Cc: Jann Horn, wang lian, Andrew Morton, linux-mm, David Hildenbrand,
Wei Yang, Christian Brauner, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest
On Tue, Aug 05, 2025 at 02:48:25PM -0400, Zi Yan wrote:
> On 5 Aug 2025, at 14:38, Jann Horn wrote:
>
> > On Tue, Aug 5, 2025 at 7:51 PM Zi Yan <ziy@nvidia.com> wrote:
> >> FORCE_READ() converts input value x to its pointer type then reads from
> >> address x. This is wrong. If x is a non-pointer, it would be caught it
> >> easily. But all FORCE_READ() callers are trying to read from a pointer and
> >> FORCE_READ() basically reads a pointer to a pointer instead of the original
> >> typed pointer. Almost no access violation was found, except the one from
> >> split_huge_page_test.
> > [...]
> >> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> >> index c20298ae98ea..b55d1809debc 100644
> >> --- a/tools/testing/selftests/mm/vm_util.h
> >> +++ b/tools/testing/selftests/mm/vm_util.h
> >> @@ -23,7 +23,7 @@
> >> * anything with it in order to trigger a read page fault. We therefore must use
> >> * volatile to stop the compiler from optimising this away.
> >> */
> >> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> >> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
> >
> > So is the problem with the old code basically that it should have been
> > something like
> >
> > #define FORCE_READ(x) (*(volatile typeof(*(x)) *)(x))
> >
> > to actually cast the normal pointer to a volatile pointer?
>
> Yeah. That works too. I would rename it to FORCE_READ_PTR to avoid
> misuse. :)
We were having this discussion on IRC, generally I'm fine with it as-is,
though my version sort of intended to make life easier by passing a ptr,
but this version makes it closer to READ_ONCE() so probably semantically a
little better. :)
>
> Best Regards,
> Yan, Zi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 17:51 [PATCH] selftests/mm: fix FORCE_READ to read input value correctly Zi Yan
2025-08-05 18:38 ` Jann Horn
@ 2025-08-05 19:00 ` Lorenzo Stoakes
2025-08-05 19:09 ` Zi Yan
2025-08-05 21:05 ` David Hildenbrand
2025-08-06 2:07 ` Wei Yang
3 siblings, 1 reply; 12+ messages in thread
From: Lorenzo Stoakes @ 2025-08-05 19:00 UTC (permalink / raw)
To: Zi Yan
Cc: wang lian, Andrew Morton, linux-mm, David Hildenbrand, Wei Yang,
Christian Brauner, Jann Horn, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest
On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
> FORCE_READ() converts input value x to its pointer type then reads from
> address x. This is wrong. If x is a non-pointer, it would be caught it
> easily. But all FORCE_READ() callers are trying to read from a pointer and
> FORCE_READ() basically reads a pointer to a pointer instead of the original
> typed pointer. Almost no access violation was found, except the one from
> split_huge_page_test.
Oops, sorry about that! I had incorrectly assumed typeof() decayed the type
when I wrote the guard-regions test code, and hadn't considered that we
were casting to (t **) and dereffing that.
And as discussed off-list, if you deref a char array like that, and are at
the end of an array, that's err... not brilliant :)
>
> Fix it by implementing a simplified READ_ONCE() instead.
I sort of intended to make this easier for pointers, but the semantics of
this are actually potentially a bit nicer - it's more like READ_ONCE() and
you're passing in the value you're actually reading so this is probably
better.
>
> Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
> Signed-off-by: Zi Yan <ziy@nvidia.com>
LGTM, so:
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
But see nits below.
> ---
> FORCE_READ() comes from commit 876320d71f51 ("selftests/mm: add self tests for
> guard page feature"). I will a separate patch to stable tree.
>
>
> tools/testing/selftests/mm/cow.c | 4 ++--
> tools/testing/selftests/mm/guard-regions.c | 2 +-
> tools/testing/selftests/mm/hugetlb-madvise.c | 4 +++-
> tools/testing/selftests/mm/migration.c | 2 +-
> tools/testing/selftests/mm/pagemap_ioctl.c | 2 +-
> tools/testing/selftests/mm/split_huge_page_test.c | 7 +++++--
> tools/testing/selftests/mm/vm_util.h | 2 +-
> 7 files changed, 14 insertions(+), 9 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c
> index d30625c18259..c744c603d688 100644
> --- a/tools/testing/selftests/mm/cow.c
> +++ b/tools/testing/selftests/mm/cow.c
> @@ -1554,8 +1554,8 @@ static void run_with_zeropage(non_anon_test_fn fn, const char *desc)
> }
>
> /* Read from the page to populate the shared zeropage. */
> - FORCE_READ(mem);
> - FORCE_READ(smem);
> + FORCE_READ(*mem);
> + FORCE_READ(*smem);
>
> fn(mem, smem, pagesize);
> munmap:
> diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c
> index b0d42eb04e3a..8dd81c0a4a5a 100644
> --- a/tools/testing/selftests/mm/guard-regions.c
> +++ b/tools/testing/selftests/mm/guard-regions.c
> @@ -145,7 +145,7 @@ static bool try_access_buf(char *ptr, bool write)
> if (write)
> *ptr = 'x';
> else
> - FORCE_READ(ptr);
> + FORCE_READ(*ptr);
> }
>
> signal_jump_set = false;
> diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c
> index 1afe14b9dc0c..c5940c0595be 100644
> --- a/tools/testing/selftests/mm/hugetlb-madvise.c
> +++ b/tools/testing/selftests/mm/hugetlb-madvise.c
> @@ -50,8 +50,10 @@ void read_fault_pages(void *addr, unsigned long nr_pages)
> unsigned long i;
>
> for (i = 0; i < nr_pages; i++) {
> + unsigned long *addr2 =
> + ((unsigned long *)(addr + (i * huge_page_size)));
> /* Prevent the compiler from optimizing out the entire loop: */
> - FORCE_READ(((unsigned long *)(addr + (i * huge_page_size))));
> + FORCE_READ(*addr2);
> }
> }
>
> diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c
> index c5a73617796a..ea945eebec2f 100644
> --- a/tools/testing/selftests/mm/migration.c
> +++ b/tools/testing/selftests/mm/migration.c
> @@ -110,7 +110,7 @@ void *access_mem(void *ptr)
> * the memory access actually happens and prevents the compiler
> * from optimizing away this entire loop.
> */
> - FORCE_READ((uint64_t *)ptr);
> + FORCE_READ(*(uint64_t *)ptr);
> }
>
> return NULL;
> diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
> index 0d4209eef0c3..e6face7c0166 100644
> --- a/tools/testing/selftests/mm/pagemap_ioctl.c
> +++ b/tools/testing/selftests/mm/pagemap_ioctl.c
> @@ -1525,7 +1525,7 @@ void zeropfn_tests(void)
>
> ret = madvise(mem, hpage_size, MADV_HUGEPAGE);
> if (!ret) {
> - FORCE_READ(mem);
> + FORCE_READ(*mem);
>
> ret = pagemap_ioctl(mem, hpage_size, &vec, 1, 0,
> 0, PAGE_IS_PFNZERO, 0, 0, PAGE_IS_PFNZERO);
> diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
> index 718daceb5282..3c761228e451 100644
> --- a/tools/testing/selftests/mm/split_huge_page_test.c
> +++ b/tools/testing/selftests/mm/split_huge_page_test.c
> @@ -440,8 +440,11 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd,
> }
> madvise(*addr, fd_size, MADV_HUGEPAGE);
>
> - for (size_t i = 0; i < fd_size; i++)
> - FORCE_READ((*addr + i));
> + for (size_t i = 0; i < fd_size; i++) {
> + char *addr2 = *addr + i;
> +
> + FORCE_READ(*addr2);
> + }
>
> if (!check_huge_file(*addr, fd_size / pmd_pagesize, pmd_pagesize)) {
> ksft_print_msg("No large pagecache folio generated, please provide a filesystem supporting large folio\n");
> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> index c20298ae98ea..b55d1809debc 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -23,7 +23,7 @@
> * anything with it in order to trigger a read page fault. We therefore must use
> * volatile to stop the compiler from optimising this away.
> */
> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
NIT: but wonder if const is necessary, and also (as discussed off-list
again :) will this work with a (void) prefixed, just to a. make it clear
we're reading but discarding and b. to avoid any possible compiler warning
on this?
I know for some reason this form doesn't generate one currently (not sure
why), but we may hit that in future.
>
> extern unsigned int __page_size;
> extern unsigned int __page_shift;
> --
> 2.47.2
>
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 19:00 ` Lorenzo Stoakes
@ 2025-08-05 19:09 ` Zi Yan
2025-08-05 19:21 ` Lorenzo Stoakes
2025-08-06 1:44 ` wang lian
0 siblings, 2 replies; 12+ messages in thread
From: Zi Yan @ 2025-08-05 19:09 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: wang lian, Andrew Morton, linux-mm, David Hildenbrand, Wei Yang,
Christian Brauner, Jann Horn, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest
On 5 Aug 2025, at 15:00, Lorenzo Stoakes wrote:
> On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
>> FORCE_READ() converts input value x to its pointer type then reads from
>> address x. This is wrong. If x is a non-pointer, it would be caught it
>> easily. But all FORCE_READ() callers are trying to read from a pointer and
>> FORCE_READ() basically reads a pointer to a pointer instead of the original
>> typed pointer. Almost no access violation was found, except the one from
>> split_huge_page_test.
>
> Oops, sorry about that! I had incorrectly assumed typeof() decayed the type
> when I wrote the guard-regions test code, and hadn't considered that we
> were casting to (t **) and dereffing that.
>
> And as discussed off-list, if you deref a char array like that, and are at
> the end of an array, that's err... not brilliant :)
>
>>
>> Fix it by implementing a simplified READ_ONCE() instead.
>
> I sort of intended to make this easier for pointers, but the semantics of
> this are actually potentially a bit nicer - it's more like READ_ONCE() and
> you're passing in the value you're actually reading so this is probably
> better.
>
>>
>> Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>
> LGTM, so:
>
> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> But see nits below.
>
>> ---
>> FORCE_READ() comes from commit 876320d71f51 ("selftests/mm: add self tests for
>> guard page feature"). I will a separate patch to stable tree.
>>
>>
>> tools/testing/selftests/mm/cow.c | 4 ++--
>> tools/testing/selftests/mm/guard-regions.c | 2 +-
>> tools/testing/selftests/mm/hugetlb-madvise.c | 4 +++-
>> tools/testing/selftests/mm/migration.c | 2 +-
>> tools/testing/selftests/mm/pagemap_ioctl.c | 2 +-
>> tools/testing/selftests/mm/split_huge_page_test.c | 7 +++++--
>> tools/testing/selftests/mm/vm_util.h | 2 +-
>> 7 files changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c
>> index d30625c18259..c744c603d688 100644
>> --- a/tools/testing/selftests/mm/cow.c
>> +++ b/tools/testing/selftests/mm/cow.c
>> @@ -1554,8 +1554,8 @@ static void run_with_zeropage(non_anon_test_fn fn, const char *desc)
>> }
>>
>> /* Read from the page to populate the shared zeropage. */
>> - FORCE_READ(mem);
>> - FORCE_READ(smem);
>> + FORCE_READ(*mem);
>> + FORCE_READ(*smem);
>>
>> fn(mem, smem, pagesize);
>> munmap:
>> diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c
>> index b0d42eb04e3a..8dd81c0a4a5a 100644
>> --- a/tools/testing/selftests/mm/guard-regions.c
>> +++ b/tools/testing/selftests/mm/guard-regions.c
>> @@ -145,7 +145,7 @@ static bool try_access_buf(char *ptr, bool write)
>> if (write)
>> *ptr = 'x';
>> else
>> - FORCE_READ(ptr);
>> + FORCE_READ(*ptr);
>> }
>>
>> signal_jump_set = false;
>> diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c
>> index 1afe14b9dc0c..c5940c0595be 100644
>> --- a/tools/testing/selftests/mm/hugetlb-madvise.c
>> +++ b/tools/testing/selftests/mm/hugetlb-madvise.c
>> @@ -50,8 +50,10 @@ void read_fault_pages(void *addr, unsigned long nr_pages)
>> unsigned long i;
>>
>> for (i = 0; i < nr_pages; i++) {
>> + unsigned long *addr2 =
>> + ((unsigned long *)(addr + (i * huge_page_size)));
>> /* Prevent the compiler from optimizing out the entire loop: */
>> - FORCE_READ(((unsigned long *)(addr + (i * huge_page_size))));
>> + FORCE_READ(*addr2);
>> }
>> }
>>
>> diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c
>> index c5a73617796a..ea945eebec2f 100644
>> --- a/tools/testing/selftests/mm/migration.c
>> +++ b/tools/testing/selftests/mm/migration.c
>> @@ -110,7 +110,7 @@ void *access_mem(void *ptr)
>> * the memory access actually happens and prevents the compiler
>> * from optimizing away this entire loop.
>> */
>> - FORCE_READ((uint64_t *)ptr);
>> + FORCE_READ(*(uint64_t *)ptr);
>> }
>>
>> return NULL;
>> diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
>> index 0d4209eef0c3..e6face7c0166 100644
>> --- a/tools/testing/selftests/mm/pagemap_ioctl.c
>> +++ b/tools/testing/selftests/mm/pagemap_ioctl.c
>> @@ -1525,7 +1525,7 @@ void zeropfn_tests(void)
>>
>> ret = madvise(mem, hpage_size, MADV_HUGEPAGE);
>> if (!ret) {
>> - FORCE_READ(mem);
>> + FORCE_READ(*mem);
>>
>> ret = pagemap_ioctl(mem, hpage_size, &vec, 1, 0,
>> 0, PAGE_IS_PFNZERO, 0, 0, PAGE_IS_PFNZERO);
>> diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
>> index 718daceb5282..3c761228e451 100644
>> --- a/tools/testing/selftests/mm/split_huge_page_test.c
>> +++ b/tools/testing/selftests/mm/split_huge_page_test.c
>> @@ -440,8 +440,11 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd,
>> }
>> madvise(*addr, fd_size, MADV_HUGEPAGE);
>>
>> - for (size_t i = 0; i < fd_size; i++)
>> - FORCE_READ((*addr + i));
>> + for (size_t i = 0; i < fd_size; i++) {
>> + char *addr2 = *addr + i;
>> +
>> + FORCE_READ(*addr2);
>> + }
>>
>> if (!check_huge_file(*addr, fd_size / pmd_pagesize, pmd_pagesize)) {
>> ksft_print_msg("No large pagecache folio generated, please provide a filesystem supporting large folio\n");
>> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
>> index c20298ae98ea..b55d1809debc 100644
>> --- a/tools/testing/selftests/mm/vm_util.h
>> +++ b/tools/testing/selftests/mm/vm_util.h
>> @@ -23,7 +23,7 @@
>> * anything with it in order to trigger a read page fault. We therefore must use
>> * volatile to stop the compiler from optimising this away.
>> */
>> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
>> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
>
> NIT: but wonder if const is necessary, and also (as discussed off-list
I just used READ_ONCE() code, but it is not necessary.
> again :) will this work with a (void) prefixed, just to a. make it clear
> we're reading but discarding and b. to avoid any possible compiler warning
> on this?
Adding (void) makes no difference, at least from godbolt.
>
> I know for some reason this form doesn't generate one currently (not sure
> why), but we may hit that in future.
Neither gcc nor clang complains without (void). My guess is that volatile
is doing something there.
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 19:09 ` Zi Yan
@ 2025-08-05 19:21 ` Lorenzo Stoakes
2025-08-06 10:34 ` Pedro Falcato
2025-08-06 1:44 ` wang lian
1 sibling, 1 reply; 12+ messages in thread
From: Lorenzo Stoakes @ 2025-08-05 19:21 UTC (permalink / raw)
To: Zi Yan
Cc: wang lian, Andrew Morton, linux-mm, David Hildenbrand, Wei Yang,
Christian Brauner, Jann Horn, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest, Pedro Falcato
+cc Pedro
On Tue, Aug 05, 2025 at 03:09:54PM -0400, Zi Yan wrote:
> On 5 Aug 2025, at 15:00, Lorenzo Stoakes wrote:
>
> > On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
> >> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> >> index c20298ae98ea..b55d1809debc 100644
> >> --- a/tools/testing/selftests/mm/vm_util.h
> >> +++ b/tools/testing/selftests/mm/vm_util.h
> >> @@ -23,7 +23,7 @@
> >> * anything with it in order to trigger a read page fault. We therefore must use
> >> * volatile to stop the compiler from optimising this away.
> >> */
> >> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> >> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
> >
> > NIT: but wonder if const is necessary, and also (as discussed off-list
>
> I just used READ_ONCE() code, but it is not necessary.
It's not end of the world though.
>
> > again :) will this work with a (void) prefixed, just to a. make it clear
> > we're reading but discarding and b. to avoid any possible compiler warning
> > on this?
>
> Adding (void) makes no difference, at least from godbolt.
Yeah I won't pretend to understand _exactly_ what the compiler is doing here, if
this is working in practice across multiple compilers and read-faulting the page
that's good enough for me :)
>
> >
> > I know for some reason this form doesn't generate one currently (not sure
> > why), but we may hit that in future.
>
> Neither gcc nor clang complains without (void). My guess is that volatile
> is doing something there.
Indeed possibly, be interesting if you or Pedro who's also playing with this
could nail down exactly what's going on here.
>
> Best Regards,
> Yan, Zi
But from my point of view this patch is fine - ship it! :)
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 17:51 [PATCH] selftests/mm: fix FORCE_READ to read input value correctly Zi Yan
2025-08-05 18:38 ` Jann Horn
2025-08-05 19:00 ` Lorenzo Stoakes
@ 2025-08-05 21:05 ` David Hildenbrand
2025-08-06 2:07 ` Wei Yang
3 siblings, 0 replies; 12+ messages in thread
From: David Hildenbrand @ 2025-08-05 21:05 UTC (permalink / raw)
To: Zi Yan, wang lian, Andrew Morton, linux-mm
Cc: Lorenzo Stoakes, Wei Yang, Christian Brauner, Jann Horn,
Kairui Song, Liam Howlett, Mark Brown, SeongJae Park, Shuah Khan,
Vlastimil Babka, linux-kernel, linux-kselftest
On 05.08.25 19:51, Zi Yan wrote:
> FORCE_READ() converts input value x to its pointer type then reads from
> address x. This is wrong. If x is a non-pointer, it would be caught it
> easily. But all FORCE_READ() callers are trying to read from a pointer and
> FORCE_READ() basically reads a pointer to a pointer instead of the original
> typed pointer. Almost no access violation was found, except the one from
> split_huge_page_test.
>
> Fix it by implementing a simplified READ_ONCE() instead.
>
> Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
> Signed-off-by: Zi Yan <ziy@nvidia.com>
> ---
Ouch, thank!
Acked-by: David Hildenbrand <david@redhat.com>
--
Cheers,
David / dhildenb
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 19:09 ` Zi Yan
2025-08-05 19:21 ` Lorenzo Stoakes
@ 2025-08-06 1:44 ` wang lian
1 sibling, 0 replies; 12+ messages in thread
From: wang lian @ 2025-08-06 1:44 UTC (permalink / raw)
To: ziy
Cc: akpm, brauner, broonie, david, jannh, liam.howlett, lianux.mm,
linux-kernel, linux-kselftest, linux-mm, lorenzo.stoakes,
richard.weiyang, ryncsn, shuah, sj, vbabka
Hi Zi Yan, Lorenzo,
Thank you for the detailed discussion. I have been following the
thread closely and it has been very insightful.
Zi Yan's fix is excellent and I appreciate the rigorous analysis.
Lorenzo's feedback has also deepened my own understanding of the
subtleties around the FORCE_READ macro.
Out of curiosity, I also checked the `(void)` prefixing on Godbolt.
As Zi Yan concluded, the resulting assembly appears identical.
I will be happy to join any future discussions regarding the exact
behavior of volatile in this context.
For this patch, it's definitely LGTM from my side as well, so.
Reviewed-by:wang lian <lianux.mm@gmail.com>
Thanks,
wang lian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 17:51 [PATCH] selftests/mm: fix FORCE_READ to read input value correctly Zi Yan
` (2 preceding siblings ...)
2025-08-05 21:05 ` David Hildenbrand
@ 2025-08-06 2:07 ` Wei Yang
3 siblings, 0 replies; 12+ messages in thread
From: Wei Yang @ 2025-08-06 2:07 UTC (permalink / raw)
To: Zi Yan
Cc: wang lian, Andrew Morton, linux-mm, Lorenzo Stoakes,
David Hildenbrand, Wei Yang, Christian Brauner, Jann Horn,
Kairui Song, Liam Howlett, Mark Brown, SeongJae Park, Shuah Khan,
Vlastimil Babka, linux-kernel, linux-kselftest
On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
>FORCE_READ() converts input value x to its pointer type then reads from
>address x. This is wrong. If x is a non-pointer, it would be caught it
>easily. But all FORCE_READ() callers are trying to read from a pointer and
>FORCE_READ() basically reads a pointer to a pointer instead of the original
>typed pointer. Almost no access violation was found, except the one from
>split_huge_page_test.
>
>Fix it by implementing a simplified READ_ONCE() instead.
>
>Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
>Signed-off-by: Zi Yan <ziy@nvidia.com>
>---
Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
--
Wei Yang
Help you, Help me
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-05 19:21 ` Lorenzo Stoakes
@ 2025-08-06 10:34 ` Pedro Falcato
2025-08-06 10:37 ` Lorenzo Stoakes
0 siblings, 1 reply; 12+ messages in thread
From: Pedro Falcato @ 2025-08-06 10:34 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Zi Yan, wang lian, Andrew Morton, linux-mm, David Hildenbrand,
Wei Yang, Christian Brauner, Jann Horn, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest
On Tue, Aug 05, 2025 at 08:21:23PM +0100, Lorenzo Stoakes wrote:
> +cc Pedro
>
> On Tue, Aug 05, 2025 at 03:09:54PM -0400, Zi Yan wrote:
> > On 5 Aug 2025, at 15:00, Lorenzo Stoakes wrote:
> >
> > > On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
> > >> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> > >> index c20298ae98ea..b55d1809debc 100644
> > >> --- a/tools/testing/selftests/mm/vm_util.h
> > >> +++ b/tools/testing/selftests/mm/vm_util.h
> > >> @@ -23,7 +23,7 @@
> > >> * anything with it in order to trigger a read page fault. We therefore must use
> > >> * volatile to stop the compiler from optimising this away.
> > >> */
> > >> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> > >> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
> > >
> > > NIT: but wonder if const is necessary, and also (as discussed off-list
> >
> > I just used READ_ONCE() code, but it is not necessary.
>
> It's not end of the world though.
>
> >
> > > again :) will this work with a (void) prefixed, just to a. make it clear
> > > we're reading but discarding and b. to avoid any possible compiler warning
> > > on this?
> >
> > Adding (void) makes no difference, at least from godbolt.
>
I disagree with adding (void), because volatile being properly propagated into
the type should hide any Wunused-value warnings (because volatile reads can have
side effects, so discarding a read is most definitely valid).
And as I was seeing in https://godbolt.org/z/jnWsET1vx yesterday, GCC (and clang)
can silently drop the volatile qualifier For Some Reason.
--
Pedro
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] selftests/mm: fix FORCE_READ to read input value correctly.
2025-08-06 10:34 ` Pedro Falcato
@ 2025-08-06 10:37 ` Lorenzo Stoakes
0 siblings, 0 replies; 12+ messages in thread
From: Lorenzo Stoakes @ 2025-08-06 10:37 UTC (permalink / raw)
To: Pedro Falcato
Cc: Zi Yan, wang lian, Andrew Morton, linux-mm, David Hildenbrand,
Wei Yang, Christian Brauner, Jann Horn, Kairui Song, Liam Howlett,
Mark Brown, SeongJae Park, Shuah Khan, Vlastimil Babka,
linux-kernel, linux-kselftest
On Wed, Aug 06, 2025 at 11:34:57AM +0100, Pedro Falcato wrote:
> On Tue, Aug 05, 2025 at 08:21:23PM +0100, Lorenzo Stoakes wrote:
> > +cc Pedro
> >
> > On Tue, Aug 05, 2025 at 03:09:54PM -0400, Zi Yan wrote:
> > > On 5 Aug 2025, at 15:00, Lorenzo Stoakes wrote:
> > >
> > > > On Tue, Aug 05, 2025 at 01:51:40PM -0400, Zi Yan wrote:
> > > >> diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
> > > >> index c20298ae98ea..b55d1809debc 100644
> > > >> --- a/tools/testing/selftests/mm/vm_util.h
> > > >> +++ b/tools/testing/selftests/mm/vm_util.h
> > > >> @@ -23,7 +23,7 @@
> > > >> * anything with it in order to trigger a read page fault. We therefore must use
> > > >> * volatile to stop the compiler from optimising this away.
> > > >> */
> > > >> -#define FORCE_READ(x) (*(volatile typeof(x) *)x)
> > > >> +#define FORCE_READ(x) (*(const volatile typeof(x) *)&(x))
> > > >
> > > > NIT: but wonder if const is necessary, and also (as discussed off-list
> > >
> > > I just used READ_ONCE() code, but it is not necessary.
> >
> > It's not end of the world though.
> >
> > >
> > > > again :) will this work with a (void) prefixed, just to a. make it clear
> > > > we're reading but discarding and b. to avoid any possible compiler warning
> > > > on this?
> > >
> > > Adding (void) makes no difference, at least from godbolt.
> >
>
> I disagree with adding (void), because volatile being properly propagated into
> the type should hide any Wunused-value warnings (because volatile reads can have
> side effects, so discarding a read is most definitely valid).
Yeah, I just wondered _why_.
I mean this is fine as-is. I believe Andrew's already taken the patch as a
hotfix anyway.
>
> And as I was seeing in https://godbolt.org/z/jnWsET1vx yesterday, GCC (and clang)
> can silently drop the volatile qualifier For Some Reason.
Ack, would love to know why, but don't have the time to explore so was hoping
you/someone else could figure it out and tell me :P
>
> --
> Pedro
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-08-06 10:37 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-05 17:51 [PATCH] selftests/mm: fix FORCE_READ to read input value correctly Zi Yan
2025-08-05 18:38 ` Jann Horn
2025-08-05 18:48 ` Zi Yan
2025-08-05 18:56 ` Lorenzo Stoakes
2025-08-05 19:00 ` Lorenzo Stoakes
2025-08-05 19:09 ` Zi Yan
2025-08-05 19:21 ` Lorenzo Stoakes
2025-08-06 10:34 ` Pedro Falcato
2025-08-06 10:37 ` Lorenzo Stoakes
2025-08-06 1:44 ` wang lian
2025-08-05 21:05 ` David Hildenbrand
2025-08-06 2:07 ` Wei Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).