https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97229
Bug ID: 97229 Summary: pointer-compare sanitizer is very slow due to __asan::IsAddressNearGlobal Product: gcc Version: 10.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: mail at milianw dot de CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at gcc dot gnu.org Target Milestone: --- I am trying to use the pointer-compare sanitizer during product development. I noticed that it is usually fine from a performance POV, but one specific code path is getting extremely slow. Quasi 99% of the CPU samples point at this backtrace: ``` <our code> __sanitizer_ptr_cmp __asanCheckForInvalidPointerPair __asanCheckForInvalidPointerPair __asan::IsInvalidPointerPair __asan::GetGlobalAddressInformation(unsigned long, unsigned long, ...) __asan::GetGlobalsForAddress(unsigned long, __asan_global*, ...) __asan::isAddressNearGlobal ``` I have tried to simulate what our code does in this simplistic example: It copies one file to another in a stupid way via mmap. The pointer comparison is within the copy() function below. ``` #include <cstdio> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <algorithm> static __attribute__((noinline)) void copy(const unsigned char *source, size_t source_size, unsigned char *target, size_t target_size) { if (target + source_size > target + target_size) { fprintf(stderr, "bad offsets: %zu %zu\n", target_size, source_size); return; } std::copy_n(source, source_size, target); } unsigned char* mapBuffer(const char *path, size_t size) { auto fd = open(path, O_CREAT | O_RDWR, 0600); if (fd == -1) { perror("failed to open file"); return nullptr; } if (posix_fallocate64(fd, 0, size) != 0) { perror("failed to resize file"); close(fd); return nullptr; } auto buffer = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (!buffer) { perror("failed to mmap file"); return nullptr; } return reinterpret_cast<unsigned char*>(buffer); } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "USAGE: ./a.out BUFFER_SIZE COPY_SIZE\n"); return 1; } const auto size_i = atoi(argv[1]); if (size_i < 0) { fprintf(stderr, "bad size: %d\n", size_i); return 1; } const auto size = static_cast<size_t>(size_i); const auto copySize_i = atoi(argv[2]); if (copySize_i < 0 || copySize_i > size_i || (size_i % copySize_i) != 0) { fprintf(stderr, "bad copy size: %d %d\n", copySize_i, size_i); return 1; } const auto copySize = static_cast<size_t>(copySize_i); auto source = mapBuffer("/tmp/source.dat", size); if (!source) { return 1; } auto target = mapBuffer("/tmp/target.dat", size); if (!target) { return 1; } for (int i = 0; i < size; i += copySize) { copy(source + i, copySize, target + i, copySize); } munmap(source, size); munmap(target, size); return 0; } ``` But that demo does not show the extreme slow down. It is actually behaving quite well, at most 10% slow down, when enabling pointer-compare with the ASAN_OPTIONS env var. In the real application, the slow-down is more in the order of 100x or more. That app links in a lot of other libraries and also runs code in multiple threads, so I suspect that the issue I'm seeing is related to the amount of globals and potentially libraries available in the application? Any idea how I could reproduce this to create a proper MWE?