sanitizer_common.cc revision cc7525951f401d61e2467f1ebc1b133205516a6c
1230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov//===-- sanitizer_common.cc -----------------------------------------------===// 2230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// 3230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// The LLVM Compiler Infrastructure 4230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// 5230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// This file is distributed under the University of Illinois Open Source 6230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// License. See LICENSE.TXT for details. 7230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// 8230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov//===----------------------------------------------------------------------===// 9230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// 10230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer 11230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov// run-time libraries. 12230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov//===----------------------------------------------------------------------===// 13230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov 14230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include "sanitizer_common.h" 15230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include "sanitizer_libc.h" 164c49666e611f06241bb8462cea7674d877241492Alexey Samsonov 17230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonovnamespace __sanitizer { 18230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov 19f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryanyuptr GetPageSizeCached() { 20f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany static uptr PageSize; 21f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany if (!PageSize) 22f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany PageSize = GetPageSize(); 23f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany return PageSize; 24f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany} 25f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany 26ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov// By default, dump to stderr. If report_fd is kInvalidFd, try to obtain file 27ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov// descriptor by opening file in report_path. 28f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonovstatic fd_t report_fd = kStderrFd; 2981dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryanystatic char report_path[4096]; // Set via __sanitizer_set_report_path. 3081dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany 31591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovstatic void (*DieCallback)(void); 32591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovvoid SetDieCallback(void (*callback)(void)) { 33591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov DieCallback = callback; 34591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov} 35591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov 36591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovvoid NORETURN Die() { 37591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov if (DieCallback) { 38591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov DieCallback(); 39591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov } 40591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov Exit(1); 41591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov} 42591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov 43591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovstatic CheckFailedCallbackType CheckFailedCallback; 44591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovvoid SetCheckFailedCallback(CheckFailedCallbackType callback) { 45591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov CheckFailedCallback = callback; 46591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov} 47591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov 48591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonovvoid NORETURN CheckFailed(const char *file, int line, const char *cond, 49591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov u64 v1, u64 v2) { 50591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov if (CheckFailedCallback) { 51591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov CheckFailedCallback(file, line, cond, v1, v2); 52591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov } 53591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov Report("Sanitizer CHECK failed: %s:%d %s (%zd, %zd)\n", file, line, cond, 54591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov v1, v2); 55591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov Die(); 56591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov} 57591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov 5884d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonovstatic void MaybeOpenReportFile() { 5984d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov if (report_fd != kInvalidFd) 6084d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov return; 6184d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov fd_t fd = internal_open(report_path, true); 6284d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov if (fd == kInvalidFd) { 6384d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov report_fd = kStderrFd; 6484d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov Report("ERROR: Can't open file: %s\n", report_path); 6584d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov Die(); 6684d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov } 6784d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov report_fd = fd; 6884d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov} 6984d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov 7084d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonovbool PrintsToTty() { 7184d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov MaybeOpenReportFile(); 7284d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov return internal_isatty(report_fd); 7384d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov} 7484d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov 75230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonovvoid RawWrite(const char *buffer) { 76230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov static const char *kRawWriteError = "RawWrite can't output requested buffer!"; 77230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov uptr length = (uptr)internal_strlen(buffer); 7884d57b4ce545d6c19effac01124749a9df0fd0a5Alexey Samsonov MaybeOpenReportFile(); 7981dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany if (length != internal_write(report_fd, buffer, length)) { 8081dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); 81230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov Die(); 82230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov } 83230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov} 84230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov 85cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonovuptr ReadFileToBuffer(const char *file_name, char **buff, 86cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov uptr *buff_size, uptr max_len) { 87f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany uptr PageSize = GetPageSizeCached(); 88f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany uptr kMinFileLen = PageSize; 89cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov uptr read_len = 0; 90cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov *buff = 0; 91cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov *buff_size = 0; 92cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov // The files we usually open are not seekable, so try different buffer sizes. 93cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 94cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov fd_t fd = internal_open(file_name, /*write*/ false); 95cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov if (fd == kInvalidFd) return 0; 96cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov UnmapOrDie(*buff, *buff_size); 97cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov *buff = (char*)MmapOrDie(size, __FUNCTION__); 98cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov *buff_size = size; 99cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov // Read up to one page at a time. 100cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov read_len = 0; 101cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov bool reached_eof = false; 102f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany while (read_len + PageSize <= size) { 103f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany uptr just_read = internal_read(fd, *buff + read_len, PageSize); 104cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov if (just_read == 0) { 105cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov reached_eof = true; 106cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov break; 107cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov } 108cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov read_len += just_read; 109cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov } 110cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov internal_close(fd); 111cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov if (reached_eof) // We've read the whole file. 112cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov break; 113cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov } 114cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov return read_len; 115cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov} 116cffe2f5c30c27234260d004b54152916ff0c45c6Alexey Samsonov 1170dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// We don't want to use std::sort to avoid including <algorithm>, as 1180dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// we may end up with two implementation of std::sort - one in instrumented 1190dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// code, and the other in runtime. 1200dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// qsort() from stdlib won't work as it calls malloc(), which results 1210dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// in deadlock in ASan allocator. 1220dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov// We re-implement in-place sorting w/o recursion as straightforward heapsort. 1234c49666e611f06241bb8462cea7674d877241492Alexey Samsonovvoid SortArray(uptr *array, uptr size) { 1240dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov if (size < 2) 1250dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov return; 1260dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov // Stage 1: insert elements to the heap. 1270dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov for (uptr i = 1; i < size; i++) { 1280dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov uptr j, p; 1290dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov for (j = i; j > 0; j = p) { 1300dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov p = (j - 1) / 2; 1310dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov if (array[j] > array[p]) 1320dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov Swap(array[j], array[p]); 1330dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov else 1340dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov break; 1350dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov } 1360dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov } 1370dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov // Stage 2: swap largest element with the last one, 1380dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov // and sink the new top. 1390dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov for (uptr i = size - 1; i > 0; i--) { 1400dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov Swap(array[0], array[i]); 1410dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov uptr j, max_ind; 1420dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov for (j = 0; j < i; j = max_ind) { 1430dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov uptr left = 2 * j + 1; 1440dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov uptr right = 2 * j + 2; 1450dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov max_ind = j; 1460dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov if (left < i && array[left] > array[max_ind]) 1470dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov max_ind = left; 1480dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov if (right < i && array[right] > array[max_ind]) 1490dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov max_ind = right; 1500dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov if (max_ind != j) 1510dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov Swap(array[j], array[max_ind]); 1520dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov else 1530dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov break; 1540dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov } 1550dc3177d6c54fafb9577254a93b2f3c4169129d7Alexey Samsonov } 1564c49666e611f06241bb8462cea7674d877241492Alexey Samsonov} 1574c49666e611f06241bb8462cea7674d877241492Alexey Samsonov 158cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany// We want to map a chunk of address space aligned to 'alignment'. 159cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany// We do it by maping a bit more and then unmaping redundant pieces. 160cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany// We probably can do it with fewer syscalls in some OS-dependent way. 161cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryanyvoid *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 162cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr PageSize = GetPageSizeCached(); 163cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany CHECK(IsPowerOfTwo(size)); 164cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany CHECK(IsPowerOfTwo(alignment)); 165cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr map_size = size + alignment; 166cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 167cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr map_end = map_res + map_size; 168cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr res = map_res; 169cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany if (res & (alignment - 1)) // Not aligned. 170cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany res = (map_res + alignment) & ~ (alignment - 1); 171cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany uptr end = res + size; 172cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany if (res != map_res) 173cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany UnmapOrDie((void*)map_res, res - map_res); 174cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany if (end != map_end) 175cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany UnmapOrDie((void*)end, map_end - end); 176cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany return (void*)res; 177cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany} 178cc7525951f401d61e2467f1ebc1b133205516a6cKostya Serebryany 179230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov} // namespace __sanitizer 18081dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany 181ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonovusing namespace __sanitizer; // NOLINT 182ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov 183ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonovextern "C" { 18481dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryanyvoid __sanitizer_set_report_path(const char *path) { 18581dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany if (!path) return; 18681dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany uptr len = internal_strlen(path); 187f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov if (len > sizeof(report_path) - 100) { 18881dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 18981dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany path[0], path[1], path[2], path[3], 19081dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany path[4], path[5], path[6], path[7]); 19181dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany Die(); 19281dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany } 193f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov internal_snprintf(report_path, sizeof(report_path), "%s.%d", path, GetPid()); 194f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov report_fd = kInvalidFd; 19581dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany} 196ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov 197ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonovvoid __sanitizer_set_report_fd(int fd) { 198f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov if (report_fd != kStdoutFd && 199f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov report_fd != kStderrFd && 200f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov report_fd != kInvalidFd) 201f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov internal_close(report_fd); 202f3457cb9c3e1ddbbea07ee97b22ca387687b72e0Alexey Samsonov report_fd = fd; 203ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov} 204ac8564e7ce11e31b1d29e92dbbcfa1a5d36bc596Alexey Samsonov} // extern "C" 205