Index: llvm/trunk/unittests/Support/MemoryTest.cpp =================================================================== --- llvm/trunk/unittests/Support/MemoryTest.cpp +++ llvm/trunk/unittests/Support/MemoryTest.cpp @@ -10,13 +10,43 @@ #include "llvm/Support/Memory.h" #include "llvm/Support/Process.h" #include "gtest/gtest.h" +#include #include +#if defined(__NetBSD__) +// clang-format off +#include +#include +#include +#include +#include +// clang-format on +#endif + using namespace llvm; using namespace sys; namespace { +bool IsMPROTECT() { +#if defined(__NetBSD__) + int mib[3]; + int paxflags; + size_t len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (sysctl(mib, 3, &paxflags, &len, NULL, 0) != 0) + err(EXIT_FAILURE, "sysctl"); + + return !!(paxflags & CTL_PROC_PAXFLAGS_MPROTECT); +#else + return false; +#endif +} + class MappedMemoryTest : public ::testing::TestWithParam { public: MappedMemoryTest() { @@ -56,7 +86,16 @@ size_t PageSize; }; +// MPROTECT prevents W+X mmaps +#define CHECK_UNSUPPORTED() \ + do { \ + if ((Flags & Memory::MF_WRITE) && (Flags & Memory::MF_EXEC) && \ + IsMPROTECT()) \ + return; \ + } while (0) + TEST_P(MappedMemoryTest, AllocAndRelease) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC); EXPECT_EQ(std::error_code(), EC); @@ -68,6 +107,7 @@ } TEST_P(MappedMemoryTest, MultipleAllocAndRelease) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC); EXPECT_EQ(std::error_code(), EC); @@ -102,6 +142,7 @@ if (Flags && !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE))) return; + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC); @@ -122,6 +163,8 @@ if (Flags && !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE))) return; + CHECK_UNSUPPORTED(); + std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags, EC); @@ -180,6 +223,11 @@ } TEST_P(MappedMemoryTest, EnabledWrite) { + // MPROTECT prevents W+X, and since this test always adds W we need + // to block any variant with X. + if ((Flags & Memory::MF_EXEC) && IsMPROTECT()) + return; + std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(2 * sizeof(int), nullptr, Flags, EC); @@ -237,6 +285,7 @@ } TEST_P(MappedMemoryTest, SuccessiveNear) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC); EXPECT_EQ(std::error_code(), EC); @@ -262,6 +311,7 @@ } TEST_P(MappedMemoryTest, DuplicateNear) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock Near((void*)(3*PageSize), 16); MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC); @@ -284,6 +334,7 @@ } TEST_P(MappedMemoryTest, ZeroNear) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock Near(nullptr, 0); MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC); @@ -310,6 +361,7 @@ } TEST_P(MappedMemoryTest, ZeroSizeNear) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock Near((void*)(4*PageSize), 0); MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC); @@ -336,6 +388,7 @@ } TEST_P(MappedMemoryTest, UnalignedNear) { + CHECK_UNSUPPORTED(); std::error_code EC; MemoryBlock Near((void*)(2*PageSize+5), 0); MemoryBlock M1 = Memory::allocateMappedMemory(15, &Near, Flags, EC);