tor-browser

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

sanitizers.h (7863B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #ifndef LIB_JXL_SANITIZERS_H_
      7 #define LIB_JXL_SANITIZERS_H_
      8 
      9 #include <cstddef>
     10 
     11 #include "lib/jxl/base/compiler_specific.h"
     12 #include "lib/jxl/base/sanitizer_definitions.h"
     13 
     14 #if JXL_MEMORY_SANITIZER
     15 #include <algorithm>
     16 #include <cinttypes>  // PRId64
     17 #include <cstdio>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include "lib/jxl/base/rect.h"
     22 #include "lib/jxl/base/status.h"
     23 #include "sanitizer/msan_interface.h"
     24 #endif
     25 
     26 namespace jxl {
     27 namespace msan {
     28 
     29 #if JXL_MEMORY_SANITIZER
     30 
     31 // Chosen so that kSanitizerSentinel is four copies of kSanitizerSentinelByte.
     32 constexpr uint8_t kSanitizerSentinelByte = 0x48;
     33 constexpr float kSanitizerSentinel = 205089.125f;
     34 
     35 static JXL_INLINE JXL_MAYBE_UNUSED void PoisonMemory(const volatile void* m,
     36                                                     size_t size) {
     37  __msan_poison(m, size);
     38 }
     39 
     40 static JXL_INLINE JXL_MAYBE_UNUSED void UnpoisonMemory(const volatile void* m,
     41                                                       size_t size) {
     42  __msan_unpoison(m, size);
     43 }
     44 
     45 static JXL_INLINE JXL_MAYBE_UNUSED void MemoryIsInitialized(
     46    const volatile void* m, size_t size) {
     47  __msan_check_mem_is_initialized(m, size);
     48 }
     49 
     50 // Mark all the bytes of an image (including padding) as poisoned bytes.
     51 template <typename Pixels>
     52 static JXL_INLINE JXL_MAYBE_UNUSED void PoisonImage(const Pixels& im) {
     53  PoisonMemory(im.bytes(), im.bytes_per_row() * im.ysize());
     54 }
     55 
     56 namespace {
     57 
     58 // Print the uninitialized regions of an image.
     59 template <typename Pixels>
     60 static JXL_INLINE JXL_MAYBE_UNUSED void PrintImageUninitialized(
     61    const Pixels& im) {
     62  fprintf(stderr,
     63          "Uninitialized regions for image of size %" PRIu64 "x%" PRIu64 ":\n",
     64          static_cast<uint64_t>(im.xsize()), static_cast<uint64_t>(im.ysize()));
     65 
     66  // A segment of uninitialized pixels in a row, in the format [first, second).
     67  typedef std::pair<size_t, size_t> PixelSegment;
     68 
     69  // Helper class to merge and print a list of rows of PixelSegment that may be
     70  // the same over big ranges of rows. This compacts the output to ranges of
     71  // rows like "[y0, y1): [x0, x1) [x2, x3)".
     72  class RowsMerger {
     73   public:
     74    // Add a new row the list of rows. If the row is the same as the previous
     75    // one it will be merged showing a range of rows [y0, y1), but if the new
     76    // row is different the current range of rows (if any) will be printed and a
     77    // new one will be started.
     78    void AddRow(size_t y, std::vector<PixelSegment>&& new_row) {
     79      if (start_y_ != -1 && new_row != segments_) {
     80        PrintRow(y);
     81      }
     82      if (new_row.empty()) {
     83        // Skip ranges with no uninitialized pixels.
     84        start_y_ = -1;
     85        segments_.clear();
     86        return;
     87      }
     88      if (start_y_ == -1) {
     89        start_y_ = y;
     90        segments_ = std::move(new_row);
     91      }
     92    }
     93 
     94    // Print the contents of the range of rows [start_y_, end_y) if any.
     95    void PrintRow(size_t end_y) {
     96      if (start_y_ == -1) return;
     97      if (segments_.empty()) {
     98        start_y_ = -1;
     99        return;
    100      }
    101      if (end_y - start_y_ > 1) {
    102        fprintf(stderr, " y=[%" PRId64 ", %" PRIu64 "):",
    103                static_cast<int64_t>(start_y_), static_cast<uint64_t>(end_y));
    104      } else {
    105        fprintf(stderr, " y=[%" PRId64 "]:", static_cast<int64_t>(start_y_));
    106      }
    107      for (const auto& seg : segments_) {
    108        if (seg.first + 1 == seg.second) {
    109          fprintf(stderr, " [%" PRId64 "]", static_cast<int64_t>(seg.first));
    110        } else {
    111          fprintf(stderr, " [%" PRId64 ", %" PRIu64 ")",
    112                  static_cast<int64_t>(seg.first),
    113                  static_cast<uint64_t>(seg.second));
    114        }
    115      }
    116      fprintf(stderr, "\n");
    117      start_y_ = -1;
    118    }
    119 
    120   private:
    121    std::vector<PixelSegment> segments_;
    122    // Row number of the first row in the range of rows that have |segments| as
    123    // the undefined segments.
    124    ssize_t start_y_ = -1;
    125  } rows_merger;
    126 
    127  class SegmentsMerger {
    128   public:
    129    void AddValue(size_t x) {
    130      if (row.empty() || row.back().second != x) {
    131        row.emplace_back(x, x + 1);
    132      } else {
    133        row.back().second = x + 1;
    134      }
    135    }
    136 
    137    std::vector<PixelSegment> row;
    138  };
    139 
    140  for (size_t y = 0; y < im.ysize(); y++) {
    141    auto* row = im.Row(y);
    142    SegmentsMerger seg_merger;
    143    size_t x = 0;
    144    while (x < im.xsize()) {
    145      intptr_t ret =
    146          __msan_test_shadow(row + x, (im.xsize() - x) * sizeof(row[0]));
    147      if (ret < 0) break;
    148      size_t next_x = x + ret / sizeof(row[0]);
    149      seg_merger.AddValue(next_x);
    150      x = next_x + 1;
    151    }
    152    rows_merger.AddRow(y, std::move(seg_merger.row));
    153  }
    154  rows_merger.PrintRow(im.ysize());
    155 }
    156 
    157 // Check that all the pixels in the provided rect of the image are initialized
    158 // (not poisoned). If any of the values is poisoned it will abort.
    159 template <typename Pixels>
    160 static JXL_INLINE JXL_MAYBE_UNUSED void CheckImageInitialized(
    161    const Pixels& im, const Rect& r, size_t c, const char* message) {
    162  JXL_DASSERT(r.x0() <= im.xsize());
    163  JXL_DASSERT(r.x0() + r.xsize() <= im.xsize());
    164  JXL_DASSERT(r.y0() <= im.ysize());
    165  JXL_DASSERT(r.y0() + r.ysize() <= im.ysize());
    166  for (size_t y = r.y0(); y < r.y0() + r.ysize(); y++) {
    167    const auto* row = im.Row(y);
    168    intptr_t ret = __msan_test_shadow(row + r.x0(), sizeof(*row) * r.xsize());
    169    if (ret != -1) {
    170      JXL_DEBUG(
    171          1,
    172          "Checking an image of %" PRIu64 " x %" PRIu64 ", rect x0=%" PRIu64
    173          ", y0=%" PRIu64
    174          ", "
    175          "xsize=%" PRIu64 ", ysize=%" PRIu64,
    176          static_cast<uint64_t>(im.xsize()), static_cast<uint64_t>(im.ysize()),
    177          static_cast<uint64_t>(r.x0()), static_cast<uint64_t>(r.y0()),
    178          static_cast<uint64_t>(r.xsize()), static_cast<uint64_t>(r.ysize()));
    179      size_t x = ret / sizeof(*row);
    180      JXL_DEBUG(1,
    181                "CheckImageInitialized failed at x=%" PRIu64 ", y=%" PRIu64
    182                ", c=%" PRIu64 ": %s",
    183                static_cast<uint64_t>(r.x0() + x), static_cast<uint64_t>(y),
    184                static_cast<uint64_t>(c), message ? message : "");
    185      PrintImageUninitialized(im);
    186    }
    187    // This will report an error if memory is not initialized.
    188    __msan_check_mem_is_initialized(row + r.x0(), sizeof(*row) * r.xsize());
    189  }
    190 }
    191 
    192 template <typename Image>
    193 static JXL_INLINE JXL_MAYBE_UNUSED void CheckImageInitialized(
    194    const Image& im, const Rect& r, const char* message) {
    195  for (size_t c = 0; c < 3; c++) {
    196    std::string str_message(message);
    197    str_message += " c=" + std::to_string(c);
    198    CheckImageInitialized(im.Plane(c), r, c, str_message.c_str());
    199  }
    200 }
    201 
    202 }  // namespace
    203 
    204 #define JXL_CHECK_IMAGE_INITIALIZED(im, r) \
    205  ::jxl::msan::CheckImageInitialized(im, r, "im=" #im ", r=" #r);
    206 
    207 #define JXL_CHECK_PLANE_INITIALIZED(im, r, c) \
    208  ::jxl::msan::CheckImageInitialized(im, r, c, "im=" #im ", r=" #r ", c=" #c);
    209 
    210 #else  // JXL_MEMORY_SANITIZER
    211 
    212 // In non-msan mode these functions don't use volatile since it is not needed
    213 // for the empty functions.
    214 
    215 static JXL_INLINE JXL_MAYBE_UNUSED void PoisonMemory(const void* m,
    216                                                     size_t size) {}
    217 static JXL_INLINE JXL_MAYBE_UNUSED void UnpoisonMemory(const void* m,
    218                                                       size_t size) {}
    219 static JXL_INLINE JXL_MAYBE_UNUSED void MemoryIsInitialized(const void* m,
    220                                                            size_t size) {}
    221 
    222 template <typename Pixels>
    223 static JXL_INLINE JXL_MAYBE_UNUSED void PoisonImage(const Pixels& im) {}
    224 
    225 #define JXL_CHECK_IMAGE_INITIALIZED(im, r)
    226 #define JXL_CHECK_PLANE_INITIALIZED(im, r, c)
    227 
    228 #endif
    229 
    230 }  // namespace msan
    231 }  // namespace jxl
    232 
    233 #endif  // LIB_JXL_SANITIZERS_H_