From ebaa9f9d351228c5522e770a16d25a71f8dec755 Mon Sep 17 00:00:00 2001 From: brody-qq Date: Sat, 8 Jun 2024 20:00:09 +0100 Subject: [PATCH] Tests/Kernel: Add more tests for shared and private mmaps Adds the following tests: * if there are multiple shared mmaps for the same file, writes to one mmap region should be visible in the other mmap regions. * if you write to a file with write(), those changes should be visible in shared mmaps for that file. * if you write to a shared mmap, those changes should be visible when you read() from the file. * if you write to a private mmap, any changes you make should not be visible when you read() the file. --- .../Kernel/TestEmptyPrivateInodeVMObject.cpp | 7 ++- Tests/Kernel/TestEmptySharedInodeVMObject.cpp | 7 ++- Tests/Kernel/TestPrivateInodeVMObject.cpp | 28 +++++++-- Tests/Kernel/TestSharedInodeVMObject.cpp | 59 ++++++++++++++++--- 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/Tests/Kernel/TestEmptyPrivateInodeVMObject.cpp b/Tests/Kernel/TestEmptyPrivateInodeVMObject.cpp index 0503f58eed3a6b..df7dad39b943f6 100644 --- a/Tests/Kernel/TestEmptyPrivateInodeVMObject.cpp +++ b/Tests/Kernel/TestEmptyPrivateInodeVMObject.cpp @@ -11,12 +11,13 @@ #include static u8* private_ptr = nullptr; +size_t const mmap_len = 0x1000; static void private_zero_length_inode_vmobject_sync_signal_handler(int) { - auto rc = msync(private_ptr, 0x1000, MS_ASYNC); + auto rc = msync(private_ptr, mmap_len, MS_ASYNC); EXPECT(rc == 0); - rc = munmap(private_ptr, 0x1000); + rc = munmap(private_ptr, mmap_len); EXPECT(rc == 0); exit(0); } @@ -32,7 +33,7 @@ TEST_CASE(private_zero_length_inode_vmobject_sync) } int fd = open("/tmp/private_msync_test", O_RDWR | O_CREAT, 0644); VERIFY(fd >= 0); - private_ptr = (u8*)mmap(nullptr, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + private_ptr = (u8*)mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); EXPECT(private_ptr != MAP_FAILED); private_ptr[0] = 0x1; VERIFY_NOT_REACHED(); diff --git a/Tests/Kernel/TestEmptySharedInodeVMObject.cpp b/Tests/Kernel/TestEmptySharedInodeVMObject.cpp index 1597015920f583..8b361073f321b2 100644 --- a/Tests/Kernel/TestEmptySharedInodeVMObject.cpp +++ b/Tests/Kernel/TestEmptySharedInodeVMObject.cpp @@ -11,12 +11,13 @@ #include static u8* shared_ptr = nullptr; +size_t const mmap_len = 0x1000; static void shared_zero_length_inode_vmobject_sync_signal_handler(int) { - auto rc = msync(shared_ptr, 0x1000, MS_ASYNC); + auto rc = msync(shared_ptr, mmap_len, MS_ASYNC); EXPECT(rc == 0); - rc = munmap(shared_ptr, 0x1000); + rc = munmap(shared_ptr, mmap_len); EXPECT(rc == 0); exit(0); } @@ -32,7 +33,7 @@ TEST_CASE(shared_zero_length_inode_vmobject_sync) } int fd = open("/tmp/shared_msync_test", O_RDWR | O_CREAT, 0644); VERIFY(fd >= 0); - shared_ptr = (u8*)mmap(nullptr, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + shared_ptr = (u8*)mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); EXPECT(shared_ptr != MAP_FAILED); shared_ptr[0] = 0x1; VERIFY_NOT_REACHED(); diff --git a/Tests/Kernel/TestPrivateInodeVMObject.cpp b/Tests/Kernel/TestPrivateInodeVMObject.cpp index 610de432cb6849..58978d86c6f56b 100644 --- a/Tests/Kernel/TestPrivateInodeVMObject.cpp +++ b/Tests/Kernel/TestPrivateInodeVMObject.cpp @@ -15,12 +15,13 @@ #include static u8* private_ptr = nullptr; +size_t const buf_len = 0x1000; static void private_non_empty_inode_vmobject_sync_signal_handler(int) { - auto rc = msync(private_ptr, 0x1000, MS_ASYNC); + auto rc = msync(private_ptr, buf_len, MS_ASYNC); EXPECT(rc == 0); - rc = munmap(private_ptr, 0x1000); + rc = munmap(private_ptr, buf_len); EXPECT(rc == 0); exit(0); } @@ -34,16 +35,31 @@ TEST_CASE(private_non_empty_inode_vmobject_sync) int rc = sigaction(SIGBUS, &new_action, nullptr); VERIFY(rc == 0); } - u8 buf[0x1000]; + int mmap_len = buf_len * 2; + u8 buf[buf_len]; memset(buf, 0, sizeof(buf)); int fd = open("/tmp/private_non_empty_msync_test", O_RDWR | O_CREAT, 0644); VERIFY(fd >= 0); auto rc = write(fd, buf, sizeof(buf)); VERIFY(rc == sizeof(buf)); - private_ptr = (u8*)mmap(nullptr, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + private_ptr = (u8*)mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); EXPECT(private_ptr != MAP_FAILED); - rc = msync(private_ptr, 0x2000, MS_ASYNC); + + // test that writes to the private mmap are not visible to read() + u8 old_val = private_ptr[0]; + private_ptr[0] = old_val + 1; + rc = msync(private_ptr, mmap_len, MS_SYNC); + VERIFY(rc == 0); + rc = lseek(fd, 0, SEEK_SET); + VERIFY(rc == 0); + u8 read_byte = 0; + rc = read(fd, &read_byte, 1); + VERIFY(rc == 1); + EXPECT(read_byte == old_val); + + // test that writes between the file length (buf_len) and mmap_len cause a SIGBUS + rc = msync(private_ptr, mmap_len, MS_ASYNC); EXPECT(rc == 0); - private_ptr[0x1001] = 0x1; + private_ptr[buf_len + 1] = 0x1; VERIFY_NOT_REACHED(); } diff --git a/Tests/Kernel/TestSharedInodeVMObject.cpp b/Tests/Kernel/TestSharedInodeVMObject.cpp index ef95259f68d1b4..5fcb1bab38a3f5 100644 --- a/Tests/Kernel/TestSharedInodeVMObject.cpp +++ b/Tests/Kernel/TestSharedInodeVMObject.cpp @@ -14,13 +14,20 @@ #include #include -static u8* shared_ptr = nullptr; +static u8* first_mmap = nullptr; +static u8* second_mmap = nullptr; +size_t const buf_len = 0x1000; static void shared_non_empty_inode_vmobject_sync_signal_handler(int) { - auto rc = msync(shared_ptr, 0x1000, MS_ASYNC); + auto rc = msync(first_mmap, buf_len, MS_ASYNC); EXPECT(rc == 0); - rc = munmap(shared_ptr, 0x1000); + rc = munmap(first_mmap, buf_len); + EXPECT(rc == 0); + + rc = msync(second_mmap, buf_len, MS_ASYNC); + EXPECT(rc == 0); + rc = munmap(second_mmap, buf_len); EXPECT(rc == 0); exit(0); } @@ -34,16 +41,52 @@ TEST_CASE(shared_non_empty_inode_vmobject_sync) int rc = sigaction(SIGBUS, &new_action, nullptr); VERIFY(rc == 0); } - u8 buf[0x1000]; + size_t mmap_len = buf_len * 2; + u8 buf[buf_len]; memset(buf, 0, sizeof(buf)); int fd = open("/tmp/shared_non_empty_msync_test", O_RDWR | O_CREAT, 0644); VERIFY(fd >= 0); auto rc = write(fd, buf, sizeof(buf)); VERIFY(rc == sizeof(buf)); - shared_ptr = (u8*)mmap(nullptr, 0x2000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - EXPECT(shared_ptr != MAP_FAILED); - rc = msync(shared_ptr, 0x2000, MS_ASYNC); + first_mmap = (u8*)mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + EXPECT(first_mmap != MAP_FAILED); + + second_mmap = (u8*)mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + EXPECT(second_mmap != MAP_FAILED); + + // test that changes to one shared mmap are visible in the other shared mmap + u8 new_val = first_mmap[0] + 1; + first_mmap[0] = new_val; + EXPECT(second_mmap[0] == new_val); + new_val = second_mmap[1] + 1; + second_mmap[1] = new_val; + EXPECT(first_mmap[1] == new_val); + + // test that changes in the shared mmap are visible to read() + new_val = first_mmap[0] + 1; + first_mmap[0] = new_val; + rc = msync(first_mmap, mmap_len, MS_SYNC); + VERIFY(rc == 0); + rc = lseek(fd, 0, SEEK_SET); + VERIFY(rc == 0); + u8 read_byte = 0; + rc = read(fd, &read_byte, 1); + VERIFY(rc == 1); + EXPECT(read_byte == new_val); + + // test that changes made by write() are visible in shared mmaps + rc = lseek(fd, 0, SEEK_SET); + VERIFY(rc == 0); + new_val = first_mmap[0] + 1; + rc = write(fd, &new_val, 1); + VERIFY(rc == 1); + EXPECT(first_mmap[0] == new_val && second_mmap[0] == new_val); + + // test that writes between the file length (buf_len) and mmap_len cause a SIGBUS + rc = msync(first_mmap, mmap_len, MS_ASYNC); + EXPECT(rc == 0); + rc = msync(second_mmap, mmap_len, MS_ASYNC); EXPECT(rc == 0); - shared_ptr[0x1001] = 0x1; + first_mmap[buf_len + 1] = 0x1; VERIFY_NOT_REACHED(); }