diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -512,97 +512,94 @@ FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg, new_end); - if (old_beg == old_end) { - old_beg = old_end = new_beg; - } else if (new_end <= old_beg || old_end <= new_beg || new_beg == new_end) { - // Poisoining whole memory. - uptr a = RoundDownTo(old_beg, granularity); - uptr b = RoundUpTo(old_end, granularity); - PoisonShadow(a, b - a, kAsanContiguousContainerOOBMagic); - - old_beg = old_end = new_beg; - } - - if (old_beg != new_beg) { - // There are two situations: we are poisoning or unpoisoning. - // WARNING: at the moment we do not poison prefixes of blocks described by - // one byte in shadow memory, so we have to unpoison prefixes of blocks with - // content. Up to (granularity - 1) bytes not-in-use may not be poisoned. + // Handle non-intersecting new/old containers separately have simpler + // intersecting case. + if (old_beg == old_end || new_beg == new_end || new_end <= old_beg || + old_end <= new_beg) { + if (old_beg != old_end) { + // Poisoning the old container. + uptr a = RoundDownTo(old_beg, granularity); + uptr b = RoundUpTo(old_end, granularity); + PoisonShadow(a, b - a, kAsanContiguousContainerOOBMagic); + } - if (new_beg < old_beg) { // We are unpoisoning + if (new_beg != new_end) { + // Unpoisoning the new container. uptr a = RoundDownTo(new_beg, granularity); - uptr c = RoundDownTo(old_beg, granularity); - // State at the moment is: - // [storage_beg, a] is poisoned and should remain like that. - // [a, c] is poisoned as well (interval may be empty if new_beg - // and old_beg are in the same block). If the container is not - // empty, first element starts somewhere in [c, c+granularity]. Because we - // do not poison prefixes, memory [c, container_end] is not poisoned and - // we won't change it. If container is empty, we have to unpoison memory - // for elements after c, so [c, container_end] - PoisonShadow(a, c - a, 0); - if (old_beg == old_end && - !AddrIsAlignedByGranularity(old_beg)) { // was empty && ends in the - // middle of a block - *(u8 *)MemToShadow(c) = static_cast(old_end - c); - } - // else: we cannot poison prefix of a block with elements or there is - // nothing to poison. - } else { // we are poisoning as beginning moved further in memory - uptr a = RoundDownTo(old_beg, granularity); - uptr c = RoundDownTo(new_beg, granularity); - // State at the moment is: - // [storage_beg, a] is poisoned and should remain like that. - // [a, c] is not poisoned (interval may be empty if new_beg and - // old_beg are in the same block) [c, container_end] is not - // poisoned. If there are remaining elements in the container: - // We have to poison [a, c], but because we do not poison prefixes, we - // cannot poison memory after c (even that there are not elements of the - // container). Up to granularity-1 unused bytes will not be poisoned. - // Otherwise: - // We have to poison the last byte as well. - PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic); - if (new_beg == old_end && - !AddrIsAlignedByGranularity(new_beg)) { // is empty && ends in the - // middle of a block - *(u8 *)MemToShadow(c) = - static_cast(kAsanContiguousContainerOOBMagic); - } + uptr b = RoundDownTo(new_end, granularity); + PoisonShadow(a, b - a, 0); + if (!AddrIsAlignedByGranularity(new_end)) + *(u8 *)MemToShadow(b) = static_cast(new_end - b); } - old_beg = new_beg; + return; } - if (old_end != new_end) { - if (old_end < new_end) { // We are unpoisoning memory - uptr a = RoundDownTo(old_end, granularity); - uptr c = RoundDownTo(new_end, granularity); - // State at the moment is: - // if container_beg < a : [container_beg, a] is correct and we will not be - // changing it. else [a, container_beg] cannot be poisoned, so we do not - // have to think about it. we have to makr as unpoisoned [a, c]. [c, end] - // is correctly poisoned. - PoisonShadow(a, c - a, 0); - if (!AddrIsAlignedByGranularity( - new_end)) // ends in the middle of a block - *(u8 *)MemToShadow(c) = static_cast(new_end - c); - } else { // We are poisoning memory + // Intersection of old and new containers is not empty. + CHECK_LT(new_beg, old_end); + CHECK_GT(new_end, old_beg); + + // There are two situations: we are poisoning or unpoisoning. + // WARNING: at the moment we do not poison prefixes of blocks described by + // one byte in shadow memory, so we have to unpoison prefixes of blocks with + // content. Up to (granularity - 1) bytes not-in-use may not be poisoned. + + if (new_beg < old_beg) { + // We are unpoisoning. + uptr a = RoundDownTo(new_beg, granularity); + uptr c = RoundDownTo(old_beg, granularity); + // State at the moment is: + // [storage_beg, a] is poisoned and should remain like that. + // [a, c] is poisoned as well (interval may be empty if new_beg + // and old_beg are in the same block). If the container is not + // empty, first element starts somewhere in [c, c+granularity]. Because we + // do not poison prefixes, memory [c, container_end] is not poisoned and + // we won't change it. If container is empty, we have to unpoison memory + // for elements after c, so [c, container_end] + PoisonShadow(a, c - a, 0); + } else if (new_beg > old_beg) { + // We are poisoning as beginning moved further in memory. + uptr a = RoundDownTo(old_beg, granularity); + uptr c = RoundDownTo(new_beg, granularity); + // State at the moment is: + // [storage_beg, a] is poisoned and should remain like that. + // [a, c] is not poisoned (interval may be empty if new_beg and + // old_beg are in the same block) [c, container_end] is not + // poisoned. If there are remaining elements in the container: + // We have to poison [a, c], but because we do not poison prefixes, we + // cannot poison memory after c (even that there are not elements of the + // container). Up to granularity-1 unused bytes will not be poisoned. + // Otherwise: + // We have to poison the last byte as well. + PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic); + } + + if (new_end > old_end) { + // We are unpoisoning memory. + uptr a = RoundDownTo(old_end, granularity); + uptr c = RoundDownTo(new_end, granularity); + // State at the moment is: + // if container_beg < a : [container_beg, a] is correct and we will not be + // changing it. else [a, container_beg] cannot be poisoned, so we do not + // have to think about it. we have to makr as unpoisoned [a, c]. [c, end] + // is correctly poisoned. + PoisonShadow(a, c - a, 0); + if (!AddrIsAlignedByGranularity(new_end)) // ends in the middle of a block + *(u8 *)MemToShadow(c) = static_cast(new_end - c); + } else if (new_end < old_end) { + // We are poisoning memory. + // State at the moment is: + // [storage_beg, a] is correctly annotated + // if container is empty after the removal, then a < container_beg and we + // will have to poison memory which is adressable only because we are not + // poisoning prefixes. + uptr a2 = RoundUpTo(new_end, granularity); + uptr c2 = RoundUpTo(old_end, granularity); + PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic); + if (!AddrIsAlignedByGranularity(new_end)) { + // Starts in the middle of the block uptr a = RoundDownTo(new_end, granularity); - // State at the moment is: - // [storage_beg, a] is correctly annotated - // if container is empty after the removal, then a < container_beg and we - // will have to poison memory which is adressable only because we are not - // poisoning prefixes. - uptr a2 = RoundUpTo(new_end, granularity); - uptr c2 = RoundUpTo(old_end, granularity); - PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic); - if (!AddrIsAlignedByGranularity( - new_end)) { // Starts in the middle of the block - if (new_end == old_beg) // empty - *(u8 *)MemToShadow(a) = kAsanContiguousContainerOOBMagic; - else // not empty - *(u8 *)MemToShadow(a) = static_cast(new_end - a); - } + *(u8 *)MemToShadow(a) = static_cast(new_end - a); } } }