| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //===---------- Linux implementation of the POSIX posix_madvise function --===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/sys/mman/posix_madvise.h" | ||
|
|
||
| #include "src/__support/OSUtil/syscall.h" // For internal syscall function. | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <sys/syscall.h> // For syscall numbers. | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| // This function is currently linux only. It has to be refactored suitably if | ||
| // posix_madvise is to be supported on non-linux operating systems also. | ||
| LLVM_LIBC_FUNCTION(int, posix_madvise, (void *addr, size_t size, int advice)) { | ||
| // POSIX_MADV_DONTNEED does nothing because the default MADV_DONTNEED may | ||
| // cause data loss, which the posix madvise does not allow. | ||
| if (advice == POSIX_MADV_DONTNEED) { | ||
| return 0; | ||
| } | ||
| long ret_val = __llvm_libc::syscall(SYS_madvise, reinterpret_cast<long>(addr), | ||
| size, advice); | ||
| return ret_val < 0 ? -ret_val : 0; | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header for madvise function --------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_SYS_MMAN_MADVISE_H | ||
| #define LLVM_LIBC_SRC_SYS_MMAN_MADVISE_H | ||
|
|
||
| #include <sys/mman.h> // For size_t and off_t | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int madvise(void *addr, size_t size, int advice); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_MMAN_MADVISE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header for mprotect function -------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_SYS_MMAN_MPROTECT_H | ||
| #define LLVM_LIBC_SRC_SYS_MMAN_MPROTECT_H | ||
|
|
||
| #include <sys/mman.h> // For size_t and off_t | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int mprotect(void *addr, size_t size, int prot); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_MMAN_MPROTECT_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header for posix_madvise function --------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_SYS_MMAN_POSIX_MADVISE_H | ||
| #define LLVM_LIBC_SRC_SYS_MMAN_POSIX_MADVISE_H | ||
|
|
||
| #include <sys/mman.h> // For size_t and off_t | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int posix_madvise(void *addr, size_t size, int advice); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_MMAN_POSIX_MADVISE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| //===-- Unittests for madvise ---------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/sys/mman/madvise.h" | ||
| #include "src/sys/mman/mmap.h" | ||
| #include "src/sys/mman/munmap.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <sys/mman.h> | ||
|
|
||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| TEST(LlvmLibcMadviseTest, NoError) { | ||
| size_t alloc_size = 128; | ||
| errno = 0; | ||
| void *addr = __llvm_libc::mmap(nullptr, alloc_size, PROT_READ, | ||
| MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
| EXPECT_EQ(0, errno); | ||
| EXPECT_NE(addr, MAP_FAILED); | ||
|
|
||
| EXPECT_THAT(__llvm_libc::madvise(addr, alloc_size, MADV_RANDOM), Succeeds()); | ||
|
|
||
| int *array = reinterpret_cast<int *>(addr); | ||
| // Reading from the memory should not crash the test. | ||
| // Since we used the MAP_ANONYMOUS flag, the contents of the newly | ||
| // allocated memory should be initialized to zero. | ||
| EXPECT_EQ(array[0], 0); | ||
| EXPECT_THAT(__llvm_libc::munmap(addr, alloc_size), Succeeds()); | ||
| } | ||
|
|
||
| TEST(LlvmLibcMadviseTest, Error_BadPtr) { | ||
| errno = 0; | ||
| EXPECT_THAT(__llvm_libc::madvise(nullptr, 8, MADV_SEQUENTIAL), Fails(ENOMEM)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| //===-- Unittests for mprotect --------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "include/signal.h" | ||
| #include "src/sys/mman/mmap.h" | ||
| #include "src/sys/mman/mprotect.h" | ||
| #include "src/sys/mman/munmap.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <sys/mman.h> | ||
|
|
||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| TEST(LlvmLibcMProtectTest, NoError) { | ||
| size_t alloc_size = 128; | ||
| errno = 0; | ||
| void *addr = __llvm_libc::mmap(nullptr, alloc_size, PROT_READ, | ||
| MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
| EXPECT_EQ(0, errno); | ||
| EXPECT_NE(addr, MAP_FAILED); | ||
|
|
||
| int *array = reinterpret_cast<int *>(addr); | ||
| // Reading from the memory should not crash the test. | ||
| // Since we used the MAP_ANONYMOUS flag, the contents of the newly | ||
| // allocated memory should be initialized to zero. | ||
| EXPECT_EQ(array[0], 0); | ||
|
|
||
| // By setting the memory protection to read and write, we should be able to | ||
| // modify that memory. | ||
| EXPECT_THAT(__llvm_libc::mprotect(addr, alloc_size, PROT_READ | PROT_WRITE), | ||
| Succeeds()); | ||
| array[0] = 1; | ||
| EXPECT_EQ(array[0], 1); | ||
|
|
||
| EXPECT_THAT(__llvm_libc::munmap(addr, alloc_size), Succeeds()); | ||
| } | ||
|
|
||
| TEST(LlvmLibcMProtectTest, Error_InvalidWrite) { | ||
| // attempting to write to a read-only protected part of memory should cause a | ||
| // segfault. | ||
| EXPECT_DEATH( | ||
| [] { | ||
| size_t alloc_size = 128; | ||
| void *addr = | ||
| __llvm_libc::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, | ||
| MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
| __llvm_libc::mprotect(addr, alloc_size, PROT_READ); | ||
|
|
||
| (reinterpret_cast<char *>(addr))[0] = 'A'; | ||
| }, | ||
| WITH_SIGNAL(SIGSEGV)); | ||
| // Reading from a write only segment may succeed on some platforms, so there's | ||
| // no test to check that. | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| //===-- Unittests for posix_madvise ---------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/sys/mman/mmap.h" | ||
| #include "src/sys/mman/munmap.h" | ||
| #include "src/sys/mman/posix_madvise.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <sys/mman.h> | ||
|
|
||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| TEST(LlvmLibcPosixMadviseTest, NoError) { | ||
| size_t alloc_size = 128; | ||
| errno = 0; | ||
| void *addr = __llvm_libc::mmap(nullptr, alloc_size, PROT_READ, | ||
| MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
| EXPECT_EQ(0, errno); | ||
| EXPECT_NE(addr, MAP_FAILED); | ||
|
|
||
| EXPECT_EQ(__llvm_libc::posix_madvise(addr, alloc_size, POSIX_MADV_RANDOM), 0); | ||
|
|
||
| int *array = reinterpret_cast<int *>(addr); | ||
| // Reading from the memory should not crash the test. | ||
| // Since we used the MAP_ANONYMOUS flag, the contents of the newly | ||
| // allocated memory should be initialized to zero. | ||
| EXPECT_EQ(array[0], 0); | ||
| EXPECT_THAT(__llvm_libc::munmap(addr, alloc_size), Succeeds()); | ||
| } | ||
|
|
||
| TEST(LlvmLibcPosixMadviseTest, Error_BadPtr) { | ||
| errno = 0; | ||
| // posix_madvise is a no-op on DONTNEED, so it shouldn't fail even with the | ||
| // nullptr. | ||
| EXPECT_EQ(__llvm_libc::posix_madvise(nullptr, 8, POSIX_MADV_DONTNEED), 0); | ||
|
|
||
| // posix_madvise doesn't set errno, but the return value is actually the error | ||
| // code. | ||
| EXPECT_EQ(__llvm_libc::posix_madvise(nullptr, 8, POSIX_MADV_SEQUENTIAL), | ||
| ENOMEM); | ||
| } |