Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "wtf/PageAllocator.h"
     33 
     34 #include "wtf/Assertions.h"
     35 #include "wtf/CPU.h"
     36 #include "wtf/CryptographicallyRandomNumber.h"
     37 
     38 #if OS(UNIX)
     39 
     40 #include <sys/mman.h>
     41 
     42 #ifndef MADV_FREE
     43 #define MADV_FREE MADV_DONTNEED
     44 #endif
     45 
     46 #ifndef MAP_ANONYMOUS
     47 #define MAP_ANONYMOUS MAP_ANON
     48 #endif
     49 
     50 #elif OS(WINDOWS)
     51 
     52 #include <windows.h>
     53 
     54 #else
     55 #error Unknown OS
     56 #endif // OS(UNIX)
     57 
     58 #include <stdio.h>
     59 
     60 namespace WTF {
     61 
     62 void* allocSuperPages(void* addr, size_t len)
     63 {
     64     ASSERT(!(len & kSuperPageOffsetMask));
     65     ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kSuperPageOffsetMask));
     66 #if OS(UNIX)
     67     char* ptr = reinterpret_cast<char*>(mmap(addr, len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
     68     RELEASE_ASSERT(ptr != MAP_FAILED);
     69     // If our requested address collided with another mapping, there's a
     70     // chance we'll get back an unaligned address. We fix this by attempting
     71     // the allocation again, but with enough slack pages that we can find
     72     // correct alignment within the allocation.
     73     if (UNLIKELY(reinterpret_cast<uintptr_t>(ptr) & kSuperPageOffsetMask)) {
     74         int ret = munmap(ptr, len);
     75         ASSERT(!ret);
     76         ptr = reinterpret_cast<char*>(mmap(0, len + kSuperPageSize - kSystemPageSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
     77         RELEASE_ASSERT(ptr != MAP_FAILED);
     78         int numSystemPagesToUnmap = kNumSystemPagesPerSuperPage - 1;
     79         int numSystemPagesBefore = (kNumSystemPagesPerSuperPage - ((reinterpret_cast<uintptr_t>(ptr) & kSuperPageOffsetMask) / kSystemPageSize)) % kNumSystemPagesPerSuperPage;
     80         ASSERT(numSystemPagesBefore <= numSystemPagesToUnmap);
     81         int numSystemPagesAfter = numSystemPagesToUnmap - numSystemPagesBefore;
     82         if (numSystemPagesBefore) {
     83             size_t beforeSize = kSystemPageSize * numSystemPagesBefore;
     84             ret = munmap(ptr, beforeSize);
     85             ASSERT(!ret);
     86             ptr += beforeSize;
     87         }
     88         if (numSystemPagesAfter) {
     89             ret = munmap(ptr + len, kSystemPageSize * numSystemPagesAfter);
     90             ASSERT(!ret);
     91         }
     92     }
     93     void* ret = ptr;
     94 #else
     95     // Windows is a lot simpler because we've designed around its
     96     // coarser-grained alignement.
     97     void* ret = VirtualAlloc(addr, len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
     98     if (!ret)
     99         ret = VirtualAlloc(0, len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    100     RELEASE_ASSERT(ret);
    101 #endif // OS(UNIX)
    102     return ret;
    103 }
    104 
    105 void freeSuperPages(void* addr, size_t len)
    106 {
    107     ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kSuperPageOffsetMask));
    108     ASSERT(!(len & kSuperPageOffsetMask));
    109 #if OS(UNIX)
    110     int ret = munmap(addr, len);
    111     ASSERT(!ret);
    112 #else
    113     BOOL ret = VirtualFree(addr, 0, MEM_RELEASE);
    114     ASSERT(ret);
    115 #endif
    116 }
    117 
    118 void setSystemPagesInaccessible(void* addr, size_t len)
    119 {
    120     ASSERT(!(len & kSystemPageOffsetMask));
    121 #if OS(UNIX)
    122     int ret = mprotect(addr, len, PROT_NONE);
    123     ASSERT(!ret);
    124 #else
    125     BOOL ret = VirtualFree(addr, len, MEM_DECOMMIT);
    126     ASSERT(ret);
    127 #endif
    128 }
    129 
    130 void decommitSystemPages(void* addr, size_t len)
    131 {
    132     ASSERT(!(len & kSystemPageOffsetMask));
    133 #if OS(UNIX)
    134     int ret = madvise(addr, len, MADV_FREE);
    135     ASSERT(!ret);
    136 #else
    137     void* ret = VirtualAlloc(addr, len, MEM_RESET, PAGE_READWRITE);
    138     ASSERT(ret);
    139 #endif
    140 }
    141 
    142 char* getRandomSuperPageBase()
    143 {
    144     uintptr_t random;
    145     random = static_cast<uintptr_t>(cryptographicallyRandomNumber());
    146 #if CPU(X86_64)
    147     random <<= 32UL;
    148     random |= static_cast<uintptr_t>(cryptographicallyRandomNumber());
    149     // This address mask gives a low liklihood of address space collisions.
    150     // We handle the situation gracefully if there is a collision.
    151 #if OS(WINDOWS)
    152     // 64-bit Windows has a bizarrely small 8TB user address space.
    153     // Allocates in the 1-5TB region.
    154     random &= (0x3ffffffffffUL & kSuperPageBaseMask);
    155     random += 0x10000000000UL;
    156 #else
    157     random &= (0x3fffffffffffUL & kSuperPageBaseMask);
    158 #endif
    159 #else // !CPU(X86_64)
    160     // This is a good range on Windows, Linux and Mac.
    161     // Allocates in the 0.5-1.5GB region.
    162     random &= (0x3fffffff & kSuperPageBaseMask);
    163     random += 0x20000000;
    164 #endif // CPU(X86_64)
    165     return reinterpret_cast<char*>(random);
    166 }
    167 
    168 } // namespace WTF
    169 
    170