[compiler-rt] r263160 - [Windows] Fix UnmapOrDie and MmapAlignedOrDie

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 27 09:26:42 PDT 2016


Hi,

I had to restore the MEM_DECOMMIT part (r267730). Tsan relies on the
old behavior.
We can think of a better fix, but I needed to contain fire and update
Go runtimes because commit window closes in few days and I will OOO
the remaining days. So a delay here would mean 6 month delay in
deployment of important fixes for Go.










On Thu, Mar 10, 2016 at 9:47 PM, Reid Kleckner via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: rnk
> Date: Thu Mar 10 14:47:26 2016
> New Revision: 263160
>
> URL: http://llvm.org/viewvc/llvm-project?rev=263160&view=rev
> Log:
> [Windows] Fix UnmapOrDie and MmapAlignedOrDie
>
> Now ASan can return virtual memory to the underlying OS. Portable
> sanitizer runtime code needs to be aware that UnmapOrDie cannot unmap
> part of previous mapping.
>
> In particular, this required changing how we implement MmapAlignedOrDie
> on Windows, which is what Allocator32 uses.
>
> The new code first attempts to allocate memory of the given size, and if
> it is appropriately aligned, returns early. If not, it frees the memory
> and attempts to reserve size + alignment bytes. In this region there
> must be an aligned address. We then free the oversized mapping and
> request a new mapping at the aligned address immediately after. However,
> a thread could allocate that virtual address in between our free and
> allocation, so we have to retry if that allocation fails. The existing
> thread creation stress test managed to trigger this condition, so the
> code isn't totally untested.
>
> Reviewers: samsonov
>
> Differential Revision: http://reviews.llvm.org/D17431
>
> Modified:
>     compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc
>     compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc
>     compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
>     compiler-rt/trunk/test/asan/TestCases/Windows/oom.cc
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc?rev=263160&r1=263159&r2=263160&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc Thu Mar 10 14:47:26 2016
> @@ -230,27 +230,6 @@ void SortArray(uptr *array, uptr size) {
>    InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
>  }
>
> -// We want to map a chunk of address space aligned to 'alignment'.
> -// We do it by maping a bit more and then unmaping redundant pieces.
> -// We probably can do it with fewer syscalls in some OS-dependent way.
> -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
> -// uptr PageSize = GetPageSizeCached();
> -  CHECK(IsPowerOfTwo(size));
> -  CHECK(IsPowerOfTwo(alignment));
> -  uptr map_size = size + alignment;
> -  uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
> -  uptr map_end = map_res + map_size;
> -  uptr res = map_res;
> -  if (res & (alignment - 1))  // Not aligned.
> -    res = (map_res + alignment) & ~(alignment - 1);
> -  uptr end = res + size;
> -  if (res != map_res)
> -    UnmapOrDie((void*)map_res, res - map_res);
> -  if (end != map_end)
> -    UnmapOrDie((void*)end, map_end - end);
> -  return (void*)res;
> -}
> -
>  const char *StripPathPrefix(const char *filepath,
>                              const char *strip_path_prefix) {
>    if (!filepath) return nullptr;
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc?rev=263160&r1=263159&r2=263160&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc Thu Mar 10 14:47:26 2016
> @@ -139,6 +139,26 @@ void UnmapOrDie(void *addr, uptr size) {
>    DecreaseTotalMmap(size);
>  }
>
> +// We want to map a chunk of address space aligned to 'alignment'.
> +// We do it by maping a bit more and then unmaping redundant pieces.
> +// We probably can do it with fewer syscalls in some OS-dependent way.
> +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
> +  CHECK(IsPowerOfTwo(size));
> +  CHECK(IsPowerOfTwo(alignment));
> +  uptr map_size = size + alignment;
> +  uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
> +  uptr map_end = map_res + map_size;
> +  uptr res = map_res;
> +  if (res & (alignment - 1))  // Not aligned.
> +    res = (map_res + alignment) & ~(alignment - 1);
> +  uptr end = res + size;
> +  if (res != map_res)
> +    UnmapOrDie((void*)map_res, res - map_res);
> +  if (end != map_end)
> +    UnmapOrDie((void*)end, map_end - end);
> +  return (void*)res;
> +}
> +
>  void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
>    uptr PageSize = GetPageSizeCached();
>    uptr p = internal_mmap(nullptr,
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc?rev=263160&r1=263159&r2=263160&view=diff
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc Thu Mar 10 14:47:26 2016
> @@ -97,7 +97,17 @@ void UnmapOrDie(void *addr, uptr size) {
>    if (!size || !addr)
>      return;
>
> -  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
> +  // Make sure that this API is only used to unmap an entire previous mapping.
> +  // Windows cannot unmap part of a previous mapping. Unfortunately,
> +  // we can't check that size matches the original size because mbi.RegionSize
> +  // doesn't describe the size of the full allocation if some of the pages were
> +  // protected.
> +  MEMORY_BASIC_INFORMATION mbi;
> +  CHECK(VirtualQuery(addr, &mbi, sizeof(mbi)));
> +  CHECK(mbi.AllocationBase == addr &&
> +        "Windows cannot unmap part of a previous mapping");
> +
> +  if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
>      Report("ERROR: %s failed to "
>             "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
>             SanitizerToolName, size, size, addr, GetLastError());
> @@ -105,6 +115,61 @@ void UnmapOrDie(void *addr, uptr size) {
>    }
>  }
>
> +// We want to map a chunk of address space aligned to 'alignment'.
> +void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
> +  CHECK(IsPowerOfTwo(size));
> +  CHECK(IsPowerOfTwo(alignment));
> +
> +  // Windows will align our allocations to at least 64K.
> +  alignment = Max(alignment, GetMmapGranularity());
> +
> +  uptr mapped_addr =
> +      (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
> +  if (!mapped_addr)
> +    ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
> +
> +  // If we got it right on the first try, return. Otherwise, unmap it and go to
> +  // the slow path.
> +  if (IsAligned(mapped_addr, alignment))
> +    return (void*)mapped_addr;
> +  if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
> +    ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
> +
> +  // If we didn't get an aligned address, overallocate, find an aligned address,
> +  // unmap, and try to allocate at that aligned address.
> +  int retries = 0;
> +  const int kMaxRetries = 10;
> +  for (; retries < kMaxRetries &&
> +         (mapped_addr == 0 || !IsAligned(mapped_addr, alignment));
> +       retries++) {
> +    // Overallocate size + alignment bytes.
> +    mapped_addr =
> +        (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
> +    if (!mapped_addr)
> +      ReportMmapFailureAndDie(size, mem_type, "allocate aligned",
> +                              GetLastError());
> +
> +    // Find the aligned address.
> +    uptr aligned_addr = RoundUpTo(mapped_addr, alignment);
> +
> +    // Free the overallocation.
> +    if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
> +      ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
> +
> +    // Attempt to allocate exactly the number of bytes we need at the aligned
> +    // address. This may fail for a number of reasons, in which case we continue
> +    // the loop.
> +    mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size,
> +                                     MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
> +  }
> +
> +  // Fail if we can't make this work quickly.
> +  if (retries == kMaxRetries && mapped_addr == 0)
> +    ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
> +
> +  return (void *)mapped_addr;
> +}
> +
>  void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
>    // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
>    // but on Win64 it does.
> @@ -119,7 +184,15 @@ void *MmapFixedNoReserve(uptr fixed_addr
>  }
>
>  void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
> -  return MmapFixedNoReserve(fixed_addr, size);
> +  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
> +      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
> +  if (p == 0) {
> +    char mem_type[30];
> +    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
> +                      fixed_addr);
> +    ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
> +  }
> +  return p;
>  }
>
>  void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
>
> Modified: compiler-rt/trunk/test/asan/TestCases/Windows/oom.cc
> URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/oom.cc?rev=263160&r1=263159&r2=263160&view=diff
> ==============================================================================
> --- compiler-rt/trunk/test/asan/TestCases/Windows/oom.cc (original)
> +++ compiler-rt/trunk/test/asan/TestCases/Windows/oom.cc Thu Mar 10 14:47:26 2016
> @@ -6,7 +6,6 @@
>  int main() {
>    while (true) {
>      void *ptr = malloc(200 * 1024 * 1024);  // 200MB
> -    free(ptr);
>    }
>  // CHECK: failed to allocate
>  }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list