diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h index 544f2e4b3268..6060d6032228 100644 --- a/compiler-rt/include/sanitizer/asan_interface.h +++ b/compiler-rt/include/sanitizer/asan_interface.h @@ -102,7 +102,7 @@ int SANITIZER_CDECL __asan_address_is_poisoned(void const volatile *addr); /// address of the first such byte. Otherwise returns 0. /// /// \param beg Start of memory region. -/// \param size Start of memory region. +/// \param size Size of memory region. /// \returns Address of first poisoned byte. void *SANITIZER_CDECL __asan_region_is_poisoned(void *beg, size_t size); diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp index b08737775991..89f6ea85d605 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -241,30 +241,32 @@ int __asan_address_is_poisoned(void const volatile *addr) { uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!size) return 0; - uptr end = beg + size; + uptr last = beg + size - 1; if (!AddrIsInMem(beg)) return beg; - if (!AddrIsInMem(end)) - return end; - CHECK_LT(beg, end); + if (!AddrIsInMem(last)) + return last; + CHECK_LE(beg, last); // First check the first and the last application bytes, - // then check the ASAN_SHADOW_GRANULARITY-aligned region by calling + // then check the ASAN_SHADOW_GRANULARITY-aligned inner region by calling // mem_is_zero on the corresponding shadow. - if (!__asan::AddressIsPoisoned(beg) && !__asan::AddressIsPoisoned(end - 1)) { + if (!__asan::AddressIsPoisoned(beg) && !__asan::AddressIsPoisoned(last)) { uptr aligned_b = RoundUpTo(beg, ASAN_SHADOW_GRANULARITY); - uptr aligned_e = RoundDownTo(end, ASAN_SHADOW_GRANULARITY); + uptr aligned_e = RoundDownTo(last, ASAN_SHADOW_GRANULARITY); if (aligned_e <= aligned_b) return 0; + if (UNLIKELY(aligned_b < beg)) // address space overflow. + return 0; uptr shadow_beg = MemToShadow(aligned_b); uptr shadow_end = MemToShadow(aligned_e); - CHECK_LE(shadow_beg, shadow_end); + CHECK_LT(shadow_beg, shadow_end); if (__sanitizer::mem_is_zero((const char*)shadow_beg, shadow_end - shadow_beg)) return 0; } // The fast check failed, so we have a poisoned byte somewhere. // Find it slowly. - for (; beg < end; beg++) + for (; beg <= last; beg++) if (__asan::AddressIsPoisoned(beg)) return beg; UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found"); diff --git a/compiler-rt/lib/asan/tests/asan_noinst_test.cpp b/compiler-rt/lib/asan/tests/asan_noinst_test.cpp index 3f7abce71472..cda3764b24f1 100644 --- a/compiler-rt/lib/asan/tests/asan_noinst_test.cpp +++ b/compiler-rt/lib/asan/tests/asan_noinst_test.cpp @@ -231,30 +231,40 @@ TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) { } // Test regions fully contained in the last 8 bytes (shadow granularity) -// before given end address of a memory range (LowMem / MidMem / HighMem). -// __asan_region_is_poisoned() should not crash for those regions. -static void TestRegionIsPoisonedNearEnd(uptr end) { +// of a memory range (LowMem / MidMem / HighMem). +static void TestIsPoisonedNearMemEnd(uptr end) { static const uptr granularity = 1ULL << 3; // shadow granularity for (uptr offset = 0; offset < granularity; ++offset) { - uptr ptr = end - offset; - for (uptr size = 1; ptr < ptr + size && ptr + size <= end + 1; ++size) { - uptr first_poisoned = __asan_region_is_poisoned(ptr, size); + const uptr first = end - offset; + for (uptr last = first; first <= last && last <= end; ++last) { + const uptr size = last - first + 1; + // __asan_region_is_poisoned() should not crash for the region. + uptr first_poisoned = __asan_region_is_poisoned(first, size); EXPECT_TRUE(first_poisoned == 0 || - (first_poisoned >= ptr && first_poisoned <= ptr + size)); + (first_poisoned >= first && first_poisoned <= last)) + << " first=" << (void*)first << " size=" << size + << " first_poisoned=" << (void*)first_poisoned; + + // __asan_region_is_poisoned() and __asan_address_is_poisoned() should + // behave consistently, i.e. both should return the same result. + if (size == 1) { + int is_poisoned = __asan_address_is_poisoned((void*)first); + EXPECT_EQ((void*)first_poisoned, is_poisoned ? (void*)first : 0); + } } } } -TEST(AddressSanitizer, IsPoisonedDoesNotCrashOnMemoryBoundaries) { +TEST(AddressSanitizer, IsPoisonedOnMemoryBoundariesTest) { using __asan::kHighMemEnd; using __asan::kMidMemBeg; using __asan::kMidMemEnd; - TestRegionIsPoisonedNearEnd(kLowMemEnd); + TestIsPoisonedNearMemEnd(kLowMemEnd); if (__asan::kMidMemBeg) // if mid memory is available - TestRegionIsPoisonedNearEnd(__asan::kMidMemEnd); + TestIsPoisonedNearMemEnd(__asan::kMidMemEnd); if (kHighMemBeg) // if high memory is available - TestRegionIsPoisonedNearEnd(__asan::kHighMemEnd); + TestIsPoisonedNearMemEnd(__asan::kHighMemEnd); } // Test __asan_load1 & friends. diff --git a/compiler-rt/test/asan/TestCases/wild_pointer.cpp b/compiler-rt/test/asan/TestCases/wild_pointer.cpp index 8969a285e565..248a85aa8e88 100644 --- a/compiler-rt/test/asan/TestCases/wild_pointer.cpp +++ b/compiler-rt/test/asan/TestCases/wild_pointer.cpp @@ -19,7 +19,7 @@ int main() { // On Windows, %p omits %0x and prints hex characters in upper case, // so we use PRIxPTR instead of %p. fprintf(stderr, "Expected bad addr: %#" PRIxPTR "\n", - reinterpret_cast(p + offset)); + reinterpret_cast(p + offset - 1)); // Flush it so the output came out before the asan report. fflush(stderr);