Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/mm: fix FORCE_READ to read input value correctly

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.

Link: https://lkml.kernel.org/r/20250805175140.241656-1-ziy@nvidia.com
Fixes: 3f6bfd4789a0 ("selftests/mm: reuse FORCE_READ to replace "asm volatile("" : "+r" (XXX));"")
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: David Hildenbrand <david@redhat.com>
Reviewed-by: wang lian <lianux.mm@gmail.com>
Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Kairui Song <ryncsn@gmail.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: SeongJae Park <sj@kernel.org>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Zi Yan and committed by
Andrew Morton
5bbc2b78 9614d8be

+14 -9
+2 -2
tools/testing/selftests/mm/cow.c
··· 1554 1554 } 1555 1555 1556 1556 /* Read from the page to populate the shared zeropage. */ 1557 - FORCE_READ(mem); 1558 - FORCE_READ(smem); 1557 + FORCE_READ(*mem); 1558 + FORCE_READ(*smem); 1559 1559 1560 1560 fn(mem, smem, pagesize); 1561 1561 munmap:
+1 -1
tools/testing/selftests/mm/guard-regions.c
··· 145 145 if (write) 146 146 *ptr = 'x'; 147 147 else 148 - FORCE_READ(ptr); 148 + FORCE_READ(*ptr); 149 149 } 150 150 151 151 signal_jump_set = false;
+3 -1
tools/testing/selftests/mm/hugetlb-madvise.c
··· 50 50 unsigned long i; 51 51 52 52 for (i = 0; i < nr_pages; i++) { 53 + unsigned long *addr2 = 54 + ((unsigned long *)(addr + (i * huge_page_size))); 53 55 /* Prevent the compiler from optimizing out the entire loop: */ 54 - FORCE_READ(((unsigned long *)(addr + (i * huge_page_size)))); 56 + FORCE_READ(*addr2); 55 57 } 56 58 } 57 59
+1 -1
tools/testing/selftests/mm/migration.c
··· 110 110 * the memory access actually happens and prevents the compiler 111 111 * from optimizing away this entire loop. 112 112 */ 113 - FORCE_READ((uint64_t *)ptr); 113 + FORCE_READ(*(uint64_t *)ptr); 114 114 } 115 115 116 116 return NULL;
+1 -1
tools/testing/selftests/mm/pagemap_ioctl.c
··· 1525 1525 1526 1526 ret = madvise(mem, hpage_size, MADV_HUGEPAGE); 1527 1527 if (!ret) { 1528 - FORCE_READ(mem); 1528 + FORCE_READ(*mem); 1529 1529 1530 1530 ret = pagemap_ioctl(mem, hpage_size, &vec, 1, 0, 1531 1531 0, PAGE_IS_PFNZERO, 0, 0, PAGE_IS_PFNZERO);
+5 -2
tools/testing/selftests/mm/split_huge_page_test.c
··· 439 439 } 440 440 madvise(*addr, fd_size, MADV_HUGEPAGE); 441 441 442 - for (size_t i = 0; i < fd_size; i++) 443 - FORCE_READ((*addr + i)); 442 + for (size_t i = 0; i < fd_size; i++) { 443 + char *addr2 = *addr + i; 444 + 445 + FORCE_READ(*addr2); 446 + } 444 447 445 448 if (!check_huge_file(*addr, fd_size / pmd_pagesize, pmd_pagesize)) { 446 449 ksft_print_msg("No large pagecache folio generated, please provide a filesystem supporting large folio\n");
+1 -1
tools/testing/selftests/mm/vm_util.h
··· 23 23 * anything with it in order to trigger a read page fault. We therefore must use 24 24 * volatile to stop the compiler from optimising this away. 25 25 */ 26 - #define FORCE_READ(x) (*(volatile typeof(x) *)x) 26 + #define FORCE_READ(x) (*(const volatile typeof(x) *)&(x)) 27 27 28 28 extern unsigned int __page_size; 29 29 extern unsigned int __page_shift;