* [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 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
* 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 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 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
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).