Index: lib/asan/asan_descriptions.h =================================================================== --- lib/asan/asan_descriptions.h +++ lib/asan/asan_descriptions.h @@ -134,6 +134,7 @@ bool GetStackAddressInformation(uptr addr, uptr access_size, StackAddressDescription *descr); +bool GetStackVariableBeginning(uptr addr, uptr *shadow_addr); struct GlobalAddressDescription { uptr addr; @@ -145,6 +146,10 @@ u8 size; void Print(const char *bug_type = "") const; + + // Return true when this descriptions points inside a same global variable + // as other. Descriptions can have different address within the variable + bool PointsInsideASameVariable (const GlobalAddressDescription &other) const; }; bool GetGlobalAddressInformation(uptr addr, uptr access_size, Index: lib/asan/asan_descriptions.cc =================================================================== --- lib/asan/asan_descriptions.cc +++ lib/asan/asan_descriptions.cc @@ -222,6 +222,15 @@ return true; } +bool GetStackVariableBeginning(uptr addr, uptr *shadow_addr) +{ + AsanThread *t = FindThreadByStackAddress(addr); + if (!t) return false; + + *shadow_addr = t->GetStackFrameVariableBeginning(addr); + return true; +} + static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, uptr access_size, uptr prev_var_end, uptr next_var_beg) { @@ -335,6 +344,26 @@ } } +bool GlobalAddressDescription::PointsInsideASameVariable + (const GlobalAddressDescription &other) const +{ + if (size == 0 || other.size == 0) + return false; + + for (unsigned i = 0; i < size; i++) + for (unsigned j = 0; j < other.size; j++) { + if (globals[i].beg == other.globals[j].beg && + globals[i].beg <= addr && + other.globals[j].beg <= other.addr && + (addr + access_size) < (globals[i].beg + globals[i].size) && + ((other.addr + other.access_size) + < (other.globals[j].beg + other.globals[j].size))) + return true; + } + + return false; +} + void StackAddressDescription::Print() const { Decorator d; char tname[128]; Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -301,14 +301,72 @@ if (!flags()->detect_invalid_pointer_pairs) return; uptr a1 = reinterpret_cast(p1); uptr a2 = reinterpret_cast(p2); - AsanChunkView chunk1 = FindHeapChunkByAddress(a1); - AsanChunkView chunk2 = FindHeapChunkByAddress(a2); - bool valid1 = chunk1.IsAllocated(); - bool valid2 = chunk2.IsAllocated(); - if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) { - GET_CALLER_PC_BP_SP; - return ReportInvalidPointerPair(pc, bp, sp, a1, a2); + + if (a1 == a2) + return; + + uptr offset = a1 < a2 ? a2 - a1 : a1 - a2; + uptr left = a1 < a2 ? a1 : a2; + uptr right = a1 < a2 ? a2 : a1; + if (offset <= 2048) { + if (__asan_region_is_poisoned(left, offset) == 0) + return; + else + goto do_error; } + + uptr shadow_offset1, shadow_offset2; + + { + ThreadRegistryLock l(&asanThreadRegistry()); + + // check whether left is a stack memory pointer + if (GetStackVariableBeginning(left, &shadow_offset1)) { + if (GetStackVariableBeginning(right - 1, &shadow_offset2) && + shadow_offset1 == shadow_offset2) + return; + else + goto do_error; + } + } + + // check whether left is a heap memory address + HeapAddressDescription hdesc1, hdesc2; + if (GetHeapAddressInformation(left, 0, &hdesc1) && + hdesc1.chunk_access.access_type == kAccessTypeInside) { + if (GetHeapAddressInformation(right, 0, &hdesc2) && + hdesc2.chunk_access.access_type == kAccessTypeInside && + (hdesc1.chunk_access.chunk_begin + == hdesc2.chunk_access.chunk_begin)) + return; + else + goto do_error; + } + // check whether left is an address of a global variable + GlobalAddressDescription gdesc1, gdesc2; + if (GetGlobalAddressInformation(left, 0, &gdesc1)) { + if (GetGlobalAddressInformation(right - 1, 0, &gdesc2) && + gdesc1.PointsInsideASameVariable (gdesc2)) + return; + else + goto do_error; + } + + { + ThreadRegistryLock l(&asanThreadRegistry()); + if (GetStackVariableBeginning(right - 1, &shadow_offset2)) + goto do_error; + } + if (GetHeapAddressInformation(right, 0, &hdesc2) || + GetGlobalAddressInformation(right - 1, 0, &gdesc2)) + goto do_error; + + /* At this point we know nothing about both a1 and a2 addresses. */ + return; + +do_error: + GET_CALLER_PC_BP_SP; + ReportInvalidPointerPair(pc, bp, sp, a1, a2); } // ----------------------- Mac-specific reports ----------------- {{{1 Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -90,6 +90,9 @@ }; bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); + // Return beginning of a stack variable in shadow memory + uptr GetStackFrameVariableBeginning(uptr addr); + bool AddrIsInStack(uptr addr); void DeleteFakeStack(int tid) { Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -346,6 +346,29 @@ return true; } +uptr AsanThread::GetStackFrameVariableBeginning(uptr addr) +{ + uptr bottom = 0; + if (AddrIsInStack(addr)) { + bottom = stack_bottom(); + } else if (has_fake_stack()) { + bottom = fake_stack()->AddrIsInFakeStack(addr); + CHECK(bottom); + } + uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. + u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); + u8 *shadow_bottom = (u8*)MemToShadow(bottom); + + while (shadow_ptr >= shadow_bottom && + (*shadow_ptr != kAsanStackLeftRedzoneMagic && + *shadow_ptr != kAsanStackMidRedzoneMagic && + *shadow_ptr != kAsanStackRightRedzoneMagic)) { + shadow_ptr--; + } + + return (uptr)shadow_ptr; +} + bool AsanThread::AddrIsInStack(uptr addr) { const auto bounds = GetStackBounds(); return addr >= bounds.bottom && addr < bounds.top;