Skip to content

Commit

Permalink
Tests/Kernel: Add more tests for shared and private mmaps
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
brody-qq authored and timschumi committed Jul 7, 2024
1 parent 3e9b269 commit ebaa9f9
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 20 deletions.
7 changes: 4 additions & 3 deletions Tests/Kernel/TestEmptyPrivateInodeVMObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
#include <sys/mman.h>

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);
}
Expand All @@ -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();
Expand Down
7 changes: 4 additions & 3 deletions Tests/Kernel/TestEmptySharedInodeVMObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
#include <sys/mman.h>

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);
}
Expand All @@ -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();
Expand Down
28 changes: 22 additions & 6 deletions Tests/Kernel/TestPrivateInodeVMObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
#include <unistd.h>

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);
}
Expand All @@ -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();
}
59 changes: 51 additions & 8 deletions Tests/Kernel/TestSharedInodeVMObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@
#include <sys/mman.h>
#include <unistd.h>

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);
}
Expand All @@ -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();
}

0 comments on commit ebaa9f9

Please sign in to comment.