tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Utils.h (12543B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef Utils_h
      6 #define Utils_h
      7 
      8 #include <pthread.h>
      9 #include <stdint.h>
     10 #include <stddef.h>
     11 #include <sys/mman.h>
     12 #include <unistd.h>
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/Atomics.h"
     15 
     16 /**
     17 * On architectures that are little endian and that support unaligned reads,
     18 * we can use direct type, but on others, we want to have a special class
     19 * to handle conversion and alignment issues.
     20 */
     21 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__))
     22 typedef uint16_t le_uint16;
     23 typedef uint32_t le_uint32;
     24 #else
     25 
     26 /**
     27 * Template that allows to find an unsigned int type from a (computed) bit size
     28 */
     29 template <int s>
     30 struct UInt {};
     31 template <>
     32 struct UInt<16> {
     33  typedef uint16_t Type;
     34 };
     35 template <>
     36 struct UInt<32> {
     37  typedef uint32_t Type;
     38 };
     39 
     40 /**
     41 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing
     42 * conversion from little endian and avoiding alignment issues.
     43 */
     44 template <typename T>
     45 class le_to_cpu {
     46 public:
     47  typedef typename UInt<16 * sizeof(T)>::Type Type;
     48 
     49  operator Type() const { return (b << (sizeof(T) * 8)) | a; }
     50 
     51  const le_to_cpu& operator=(const Type& v) {
     52    a = v & ((1 << (sizeof(T) * 8)) - 1);
     53    b = v >> (sizeof(T) * 8);
     54    return *this;
     55  }
     56 
     57  le_to_cpu() {}
     58  explicit le_to_cpu(const Type& v) { operator=(v); }
     59 
     60  const le_to_cpu& operator+=(const Type& v) {
     61    return operator=(operator Type() + v);
     62  }
     63 
     64  const le_to_cpu& operator++(int) { return operator=(operator Type() + 1); }
     65 
     66 private:
     67  T a, b;
     68 };
     69 
     70 /**
     71 * Type definitions
     72 */
     73 typedef le_to_cpu<unsigned char> le_uint16;
     74 typedef le_to_cpu<le_uint16> le_uint32;
     75 #endif
     76 
     77 struct AutoCloseFD {
     78  const int fd;
     79 
     80  MOZ_IMPLICIT AutoCloseFD(int fd) : fd(fd) {}
     81  ~AutoCloseFD() {
     82    if (fd != -1) close(fd);
     83  }
     84  operator int() const { return fd; }
     85 };
     86 
     87 extern mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gPageSize;
     88 
     89 /**
     90 * Page alignment helpers
     91 */
     92 static size_t PageSize() {
     93  if (!gPageSize) {
     94    gPageSize = sysconf(_SC_PAGESIZE);
     95  }
     96 
     97  return gPageSize;
     98 }
     99 
    100 static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment) {
    101  return ptr & ~(alignment - 1);
    102 }
    103 
    104 template <typename T>
    105 static inline T* AlignedPtr(T* ptr, size_t alignment) {
    106  return reinterpret_cast<T*>(
    107      AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
    108 }
    109 
    110 template <typename T>
    111 static inline T PageAlignedPtr(T ptr) {
    112  return AlignedPtr(ptr, PageSize());
    113 }
    114 
    115 static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment) {
    116  return AlignedPtr(ptr + alignment - 1, alignment);
    117 }
    118 
    119 template <typename T>
    120 static inline T* AlignedEndPtr(T* ptr, size_t alignment) {
    121  return reinterpret_cast<T*>(
    122      AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
    123 }
    124 
    125 template <typename T>
    126 static inline T PageAlignedEndPtr(T ptr) {
    127  return AlignedEndPtr(ptr, PageSize());
    128 }
    129 
    130 static inline size_t AlignedSize(size_t size, size_t alignment) {
    131  return (size + alignment - 1) & ~(alignment - 1);
    132 }
    133 
    134 static inline size_t PageAlignedSize(size_t size) {
    135  return AlignedSize(size, PageSize());
    136 }
    137 
    138 static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment) {
    139  return ptr % alignment == 0;
    140 }
    141 
    142 template <typename T>
    143 static inline bool IsAlignedPtr(T* ptr, size_t alignment) {
    144  return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment);
    145 }
    146 
    147 template <typename T>
    148 static inline bool IsPageAlignedPtr(T ptr) {
    149  return IsAlignedPtr(ptr, PageSize());
    150 }
    151 
    152 static inline bool IsAlignedSize(size_t size, size_t alignment) {
    153  return size % alignment == 0;
    154 }
    155 
    156 static inline bool IsPageAlignedSize(size_t size) {
    157  return IsAlignedSize(size, PageSize());
    158 }
    159 
    160 static inline size_t PageNumber(size_t size) {
    161  return (size + PageSize() - 1) / PageSize();
    162 }
    163 
    164 /**
    165 * MemoryRange stores a pointer, size pair.
    166 */
    167 class MemoryRange {
    168 public:
    169  MemoryRange(void* buf, size_t length) : buf(buf), length(length) {}
    170 
    171  void Assign(void* b, size_t len) {
    172    buf = b;
    173    length = len;
    174  }
    175 
    176  void Assign(const MemoryRange& other) {
    177    buf = other.buf;
    178    length = other.length;
    179  }
    180 
    181  void* get() const { return buf; }
    182 
    183  operator void*() const { return buf; }
    184 
    185  operator unsigned char*() const {
    186    return reinterpret_cast<unsigned char*>(buf);
    187  }
    188 
    189  bool operator==(void* ptr) const { return buf == ptr; }
    190 
    191  bool operator==(unsigned char* ptr) const { return buf == ptr; }
    192 
    193  void* operator+(off_t offset) const {
    194    return reinterpret_cast<char*>(buf) + offset;
    195  }
    196 
    197  /**
    198   * Returns whether the given address is within the mapped range
    199   */
    200  bool Contains(void* ptr) const {
    201    return (ptr >= buf) && (ptr < reinterpret_cast<char*>(buf) + length);
    202  }
    203 
    204  /**
    205   * Returns the length of the mapped range
    206   */
    207  size_t GetLength() const { return length; }
    208 
    209  static MemoryRange mmap(void* addr, size_t length, int prot, int flags,
    210                          int fd, off_t offset) {
    211    return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length);
    212  }
    213 
    214 private:
    215  void* buf;
    216  size_t length;
    217 };
    218 
    219 /**
    220 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
    221 * a simple void * or unsigned char *.
    222 *
    223 * It is defined as a derivative of a template that allows to use a
    224 * different unmapping strategy.
    225 */
    226 template <typename T>
    227 class GenericMappedPtr : public MemoryRange {
    228 public:
    229  GenericMappedPtr(void* buf, size_t length) : MemoryRange(buf, length) {}
    230  explicit GenericMappedPtr(const MemoryRange& other) : MemoryRange(other) {}
    231  GenericMappedPtr() : MemoryRange(MAP_FAILED, 0) {}
    232 
    233  void Assign(void* b, size_t len) {
    234    if (get() != MAP_FAILED) static_cast<T*>(this)->munmap(get(), GetLength());
    235    MemoryRange::Assign(b, len);
    236  }
    237 
    238  void Assign(const MemoryRange& other) {
    239    Assign(other.get(), other.GetLength());
    240  }
    241 
    242  ~GenericMappedPtr() {
    243    if (get() != MAP_FAILED) static_cast<T*>(this)->munmap(get(), GetLength());
    244  }
    245 
    246  void release() { MemoryRange::Assign(MAP_FAILED, 0); }
    247 };
    248 
    249 struct MappedPtr : public GenericMappedPtr<MappedPtr> {
    250  MappedPtr(void* buf, size_t length)
    251      : GenericMappedPtr<MappedPtr>(buf, length) {}
    252  MOZ_IMPLICIT MappedPtr(const MemoryRange& other)
    253      : GenericMappedPtr<MappedPtr>(other) {}
    254  MappedPtr() : GenericMappedPtr<MappedPtr>() {}
    255 
    256 private:
    257  friend class GenericMappedPtr<MappedPtr>;
    258  void munmap(void* buf, size_t length) { ::munmap(buf, length); }
    259 };
    260 
    261 /**
    262 * UnsizedArray is a way to access raw arrays of data in memory.
    263 *
    264 *   struct S { ... };
    265 *   UnsizedArray<S> a(buf);
    266 *   UnsizedArray<S> b; b.Init(buf);
    267 *
    268 * This is roughly equivalent to
    269 *   const S *a = reinterpret_cast<const S *>(buf);
    270 *   const S *b = nullptr; b = reinterpret_cast<const S *>(buf);
    271 *
    272 * An UnsizedArray has no known length, and it's up to the caller to make
    273 * sure the accessed memory is mapped and makes sense.
    274 */
    275 template <typename T>
    276 class UnsizedArray {
    277 public:
    278  typedef size_t idx_t;
    279 
    280  /**
    281   * Constructors and Initializers
    282   */
    283  UnsizedArray() : contents(nullptr) {}
    284  explicit UnsizedArray(const void* buf)
    285      : contents(reinterpret_cast<const T*>(buf)) {}
    286 
    287  void Init(const void* buf) {
    288    MOZ_ASSERT(contents == nullptr);
    289    contents = reinterpret_cast<const T*>(buf);
    290  }
    291 
    292  /**
    293   * Returns the nth element of the array
    294   */
    295  const T& operator[](const idx_t index) const {
    296    MOZ_ASSERT(contents);
    297    return contents[index];
    298  }
    299 
    300  operator const T*() const { return contents; }
    301  /**
    302   * Returns whether the array points somewhere
    303   */
    304  explicit operator bool() const { return contents != nullptr; }
    305 
    306 private:
    307  const T* contents;
    308 };
    309 
    310 /**
    311 * Array, like UnsizedArray, is a way to access raw arrays of data in memory.
    312 * Unlike UnsizedArray, it has a known length, and is enumerable with an
    313 * iterator.
    314 *
    315 *   struct S { ... };
    316 *   Array<S> a(buf, len);
    317 *   UnsizedArray<S> b; b.Init(buf, len);
    318 *
    319 * In the above examples, len is the number of elements in the array. It is
    320 * also possible to initialize an Array with the buffer size:
    321 *
    322 *   Array<S> c; c.InitSize(buf, size);
    323 *
    324 * It is also possible to initialize an Array in two steps, only providing
    325 * one data at a time:
    326 *
    327 *   Array<S> d;
    328 *   d.Init(buf);
    329 *   d.Init(len); // or d.InitSize(size);
    330 *
    331 */
    332 template <typename T>
    333 class Array : public UnsizedArray<T> {
    334 public:
    335  typedef typename UnsizedArray<T>::idx_t idx_t;
    336 
    337  /**
    338   * Constructors and Initializers
    339   */
    340  Array() : UnsizedArray<T>(), length(0) {}
    341  Array(const void* buf, const idx_t length)
    342      : UnsizedArray<T>(buf), length(length) {}
    343 
    344  void Init(const void* buf) { UnsizedArray<T>::Init(buf); }
    345 
    346  void Init(const idx_t len) {
    347    MOZ_ASSERT(length == 0);
    348    length = len;
    349  }
    350 
    351  void InitSize(const idx_t size) { Init(size / sizeof(T)); }
    352 
    353  void Init(const void* buf, const idx_t len) {
    354    UnsizedArray<T>::Init(buf);
    355    Init(len);
    356  }
    357 
    358  void InitSize(const void* buf, const idx_t size) {
    359    UnsizedArray<T>::Init(buf);
    360    InitSize(size);
    361  }
    362 
    363  /**
    364   * Returns the nth element of the array
    365   */
    366  const T& operator[](const idx_t index) const {
    367    MOZ_ASSERT(index < length);
    368    MOZ_ASSERT(operator bool());
    369    return UnsizedArray<T>::operator[](index);
    370  }
    371 
    372  /**
    373   * Returns the number of elements in the array
    374   */
    375  idx_t numElements() const { return length; }
    376 
    377  /**
    378   * Returns whether the array points somewhere and has at least one element.
    379   */
    380  explicit operator bool() const {
    381    return (length > 0) && UnsizedArray<T>::operator bool();
    382  }
    383 
    384  /**
    385   * Iterator for an Array. Use is similar to that of STL const_iterators:
    386   *
    387   *   struct S { ... };
    388   *   Array<S> a(buf, len);
    389   *   for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
    390   *     // Do something with *it.
    391   *   }
    392   */
    393  class iterator {
    394   public:
    395    iterator() : item(nullptr) {}
    396 
    397    const T& operator*() const { return *item; }
    398 
    399    const T* operator->() const { return item; }
    400 
    401    iterator& operator++() {
    402      ++item;
    403      return *this;
    404    }
    405 
    406    bool operator<(const iterator& other) const { return item < other.item; }
    407 
    408   protected:
    409    friend class Array<T>;
    410    explicit iterator(const T& item) : item(&item) {}
    411 
    412   private:
    413    const T* item;
    414  };
    415 
    416  /**
    417   * Returns an iterator pointing at the beginning of the Array
    418   */
    419  iterator begin() const {
    420    if (length) return iterator(UnsizedArray<T>::operator[](0));
    421    return iterator();
    422  }
    423 
    424  /**
    425   * Returns an iterator pointing past the end of the Array
    426   */
    427  iterator end() const {
    428    if (length) return iterator(UnsizedArray<T>::operator[](length));
    429    return iterator();
    430  }
    431 
    432  /**
    433   * Reverse iterator for an Array. Use is similar to that of STL
    434   * const_reverse_iterators:
    435   *
    436   *   struct S { ... };
    437   *   Array<S> a(buf, len);
    438   *   for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) {
    439   *     // Do something with *it.
    440   *   }
    441   */
    442  class reverse_iterator {
    443   public:
    444    reverse_iterator() : item(nullptr) {}
    445 
    446    const T& operator*() const {
    447      const T* tmp = item;
    448      return *--tmp;
    449    }
    450 
    451    const T* operator->() const { return &operator*(); }
    452 
    453    reverse_iterator& operator++() {
    454      --item;
    455      return *this;
    456    }
    457 
    458    bool operator<(const reverse_iterator& other) const {
    459      return item > other.item;
    460    }
    461 
    462   protected:
    463    friend class Array<T>;
    464    explicit reverse_iterator(const T& item) : item(&item) {}
    465 
    466   private:
    467    const T* item;
    468  };
    469 
    470  /**
    471   * Returns a reverse iterator pointing at the end of the Array
    472   */
    473  reverse_iterator rbegin() const {
    474    if (length) return reverse_iterator(UnsizedArray<T>::operator[](length));
    475    return reverse_iterator();
    476  }
    477 
    478  /**
    479   * Returns a reverse iterator pointing past the beginning of the Array
    480   */
    481  reverse_iterator rend() const {
    482    if (length) return reverse_iterator(UnsizedArray<T>::operator[](0));
    483    return reverse_iterator();
    484  }
    485 
    486 private:
    487  idx_t length;
    488 };
    489 
    490 /**
    491 * Transforms a pointer-to-function to a pointer-to-object pointing at the
    492 * same address.
    493 */
    494 template <typename T>
    495 void* FunctionPtr(T func) {
    496  union {
    497    void* ptr;
    498    T func;
    499  } f;
    500  f.func = func;
    501  return f.ptr;
    502 }
    503 
    504 class AutoLock {
    505 public:
    506  explicit AutoLock(pthread_mutex_t* mutex) : mutex(mutex) {
    507    if (pthread_mutex_lock(mutex)) MOZ_CRASH("pthread_mutex_lock failed");
    508  }
    509  ~AutoLock() {
    510    if (pthread_mutex_unlock(mutex)) MOZ_CRASH("pthread_mutex_unlock failed");
    511  }
    512 
    513 private:
    514  pthread_mutex_t* mutex;
    515 };
    516 
    517 #endif /* Utils_h */