brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · ed20dc3 Raw
172 lines · cpp
1// RUN: %clangxx_asan -fexceptions -O %s -o %t && %env_asan_opts=detect_stack_use_after_return=0 %run %t2//3// Test __sanitizer_copy_contiguous_container_annotations.4 5#include <algorithm>6#include <iostream>7#include <memory>8#include <numeric>9#include <vector>10 11#include <assert.h>12#include <sanitizer/asan_interface.h>13#include <stdio.h>14#include <stdlib.h>15#include <string.h>16 17static constexpr size_t kGranularity = 8;18 19template <class T> static constexpr T RoundDown(T x) {20  return reinterpret_cast<T>(reinterpret_cast<uintptr_t>(x) &21                             ~(kGranularity - 1));22}23template <class T> static constexpr T RoundUp(T x) {24  return reinterpret_cast<T>(25      RoundDown(reinterpret_cast<uintptr_t>(x) + kGranularity - 1));26}27 28static std::vector<int> GetPoisonedState(char *begin, char *end) {29  std::vector<int> result;30  for (char *ptr = begin; ptr != end; ++ptr) {31    result.push_back(__asan_address_is_poisoned(ptr));32  }33  return result;34}35 36static void RandomPoison(char *beg, char *end) {37  assert(beg == RoundDown(beg));38  assert(end == RoundDown(end));39  __asan_poison_memory_region(beg, end - beg);40  for (beg = RoundUp(beg); beg < end; beg += kGranularity) {41    __asan_unpoison_memory_region(beg, rand() % (kGranularity + 1));42  }43}44 45template <bool benchmark>46static void Test(size_t capacity, size_t off_src, size_t off_dst,47                 char *src_buffer_beg, char *src_buffer_end,48                 char *dst_buffer_beg, char *dst_buffer_end) {49  size_t dst_buffer_size = dst_buffer_end - dst_buffer_beg;50  char *src_beg = src_buffer_beg + off_src;51  char *src_end = src_beg + capacity;52 53  char *dst_beg = dst_buffer_beg + off_dst;54  char *dst_end = dst_beg + capacity;55  if (benchmark) {56    __sanitizer_copy_contiguous_container_annotations(src_beg, src_end, dst_beg,57                                                      dst_end);58    return;59  }60 61  std::vector<int> src_poison_states =62      GetPoisonedState(src_buffer_beg, src_buffer_end);63  std::vector<int> dst_poison_before =64      GetPoisonedState(dst_buffer_beg, dst_buffer_end);65  __sanitizer_copy_contiguous_container_annotations(src_beg, src_end, dst_beg,66                                                    dst_end);67  std::vector<int> dst_poison_after =68      GetPoisonedState(dst_buffer_beg, dst_buffer_end);69 70  // Create ideal copy of src over dst.71  std::vector<int> dst_poison_exp = dst_poison_before;72  for (size_t cur = 0; cur < capacity; ++cur)73    dst_poison_exp[off_dst + cur] = src_poison_states[off_src + cur];74 75  // Unpoison prefixes of Asan granules.76  for (size_t cur = dst_buffer_size - 1; cur > 0; --cur) {77    if (cur % kGranularity != 0 && !dst_poison_exp[cur])78      dst_poison_exp[cur - 1] = 0;79  }80 81  if (dst_poison_after != dst_poison_exp) {82    std::cerr << "[" << off_dst << ", " << off_dst + capacity << ")\n";83    for (size_t i = 0; i < dst_poison_after.size(); ++i) {84      std::cerr << i << ":\t" << dst_poison_before[i] << "\t"85                << dst_poison_after[i] << "\t" << dst_poison_exp[i] << "\n";86    }87    std::cerr << "----------\n";88 89    assert(dst_poison_after == dst_poison_exp);90  }91}92 93template <bool benchmark>94static void TestNonOverlappingContainers(size_t capacity, size_t off_src,95                                         size_t off_dst) {96  // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).97  // Allocate buffers to have additional granule before and after tested ranges.98  off_src += kGranularity;99  off_dst += kGranularity;100  size_t src_buffer_size = RoundUp(off_src + capacity) + kGranularity;101  size_t dst_buffer_size = RoundUp(off_dst + capacity) + kGranularity;102 103  std::unique_ptr<char[]> src_buffer =104      std::make_unique<char[]>(src_buffer_size);105  std::unique_ptr<char[]> dst_buffer =106      std::make_unique<char[]>(dst_buffer_size);107 108  char *src_buffer_beg = src_buffer.get();109  char *src_buffer_end = src_buffer_beg + src_buffer_size;110  assert(RoundDown(src_buffer_beg) == src_buffer_beg);111 112  char *dst_buffer_beg = dst_buffer.get();113  char *dst_buffer_end = dst_buffer_beg + dst_buffer_size;114  assert(RoundDown(dst_buffer_beg) == dst_buffer_beg);115 116  for (int i = 0; i < 35; i++) {117    if (!benchmark || !i) {118      RandomPoison(src_buffer_beg, src_buffer_end);119      RandomPoison(dst_buffer_beg, dst_buffer_end);120    }121 122    Test<benchmark>(capacity, off_src, off_dst, src_buffer_beg, src_buffer_end,123                    dst_buffer_beg, dst_buffer_end);124  }125 126  __asan_unpoison_memory_region(src_buffer_beg, src_buffer_size);127  __asan_unpoison_memory_region(dst_buffer_beg, dst_buffer_size);128}129 130template <bool benchmark>131static void TestOverlappingContainers(size_t capacity, size_t off_src,132                                      size_t off_dst) {133  // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).134  // Allocate buffers to have additional granule before and after tested ranges.135  off_src += kGranularity;136  off_dst += kGranularity;137  size_t buffer_size =138      RoundUp(std::max(off_src, off_dst) + capacity) + kGranularity;139 140  // Use unique_ptr with a custom deleter to manage the buffer141  std::unique_ptr<char[]> buffer = std::make_unique<char[]>(buffer_size);142 143  char *buffer_beg = buffer.get();144  char *buffer_end = buffer_beg + buffer_size;145  assert(RoundDown(buffer_beg) == buffer_beg);146 147  for (int i = 0; i < 35; i++) {148    if (!benchmark || !i)149      RandomPoison(buffer_beg, buffer_end);150    Test<benchmark>(capacity, off_src, off_dst, buffer_beg, buffer_end,151                    buffer_beg, buffer_end);152  }153 154  __asan_unpoison_memory_region(buffer_beg, buffer_size);155}156 157int main(int argc, char **argv) {158  int n = argc == 1 ? 64 : atoi(argv[1]);159  for (size_t off_src = 0; off_src < kGranularity; off_src++) {160    for (size_t off_dst = 0; off_dst < kGranularity; off_dst++) {161      for (int capacity = 0; capacity <= n; capacity++) {162        if (n < 1024) {163          TestNonOverlappingContainers<false>(capacity, off_src, off_dst);164          TestOverlappingContainers<false>(capacity, off_src, off_dst);165        } else {166          TestNonOverlappingContainers<true>(capacity, off_src, off_dst);167          TestOverlappingContainers<true>(capacity, off_src, off_dst);168        }169      }170    }171  }172}