sync the repo
[hiphop-php.git] / hphp / runtime / vm / jit / vm-protect.cpp
blob2c96e4e4d433b4e3cf19e523c2ff0f6764d9644f
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/vm-protect.h"
19 #ifndef NDEBUG
21 #include "hphp/runtime/base/rds.h"
22 #include "hphp/runtime/vm/vm-regs.h"
24 #include <folly/portability/SysMman.h>
25 #include <folly/portability/Unistd.h>
27 namespace HPHP::jit {
29 namespace {
31 std::mutex s_lock;
32 std::atomic<void*> s_fakeRdsBase{nullptr};
33 __thread const VMProtect* tl_active_prot{nullptr};
35 void protect() {
36 if (UNLIKELY(!s_fakeRdsBase.load(std::memory_order_acquire))) {
37 std::lock_guard<std::mutex> guard(s_lock);
38 if (!s_fakeRdsBase.load(std::memory_order_acquire)) {
39 rds::tl_base = nullptr;
40 rds::threadInit(false /* shouldRegister */);
41 regState() = VMRegState::DIRTY;
43 // The current thread may attempt to read the Gen numbers of the normal
44 // portion of rds. These will all be invalid. No writes to non-persistent
45 // rds should occur while this guard is active. Leave the first page
46 // unprotected since surprise flags live there and we still do things in
47 // the jit that could write to them (like allocating request memory).
48 auto const base =
49 static_cast<char*>(rds::tl_base) + sysconf(_SC_PAGESIZE);
50 auto const protlen = rds::localSection().end() - base;
51 if (protlen > 0) {
52 auto const result = mprotect(base, protlen, PROT_READ);
53 always_assert(result == 0);
55 s_fakeRdsBase.store(rds::tl_base, std::memory_order_release);
58 rds::tl_base = s_fakeRdsBase.load(std::memory_order_acquire);
60 VMProtect::is_protected = true;
63 void unprotect(void* base) {
64 assertx(rds::tl_base == s_fakeRdsBase.load(std::memory_order_acquire));
65 rds::tl_base = base;
66 VMProtect::is_protected = false;
71 __thread bool VMProtect::is_protected{false};
73 VMProtect::VMProtect()
74 : m_oldBase(rds::tl_base)
76 if (is_protected) return;
78 assertx(tl_active_prot == nullptr);
79 tl_active_prot = this;
80 protect();
83 VMProtect::~VMProtect() {
84 if (tl_active_prot != this) return;
86 unprotect(m_oldBase);
87 tl_active_prot = nullptr;
90 VMProtect::Pause::Pause() {
91 if (!VMProtect::is_protected) {
92 m_active = false;
93 return;
95 if (auto const prot = tl_active_prot) {
96 unprotect(prot->m_oldBase);
100 VMProtect::Pause::~Pause() {
101 if (!m_active) return;
102 if (tl_active_prot) protect();
107 #endif