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?

Reply via email to