28
28
#include " swift/Runtime/Mutex.h"
29
29
#include " swift/Runtime/Once.h"
30
30
#include " swift/Strings.h"
31
+ #include " llvm/ADT/StringExtras.h"
31
32
#include < algorithm>
32
33
#include < cctype>
33
34
#include < cinttypes>
@@ -5805,30 +5806,6 @@ bool swift::_swift_debug_metadataAllocationIterationEnabled = false;
5805
5806
const void * const swift::_swift_debug_allocationPoolPointer = &AllocationPool;
5806
5807
std::atomic<const void *> swift::_swift_debug_metadataAllocationBacktraceList;
5807
5808
5808
- static void checkAllocatorDebugEnvironmentVariable (void *context) {
5809
- _swift_debug_metadataAllocationIterationEnabled
5810
- = runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION ();
5811
- if (!_swift_debug_metadataAllocationIterationEnabled) {
5812
- if (runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING ())
5813
- swift::warning (RuntimeErrorFlagNone,
5814
- " Warning: SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING "
5815
- " without SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION "
5816
- " has no effect.\n " );
5817
- return ;
5818
- }
5819
-
5820
- // Write a PoolTrailer to the end of InitialAllocationPool and shrink
5821
- // the pool accordingly.
5822
- auto poolCopy = AllocationPool.load (std::memory_order_relaxed);
5823
- assert (poolCopy.Begin == InitialAllocationPool.Pool );
5824
- size_t newPoolSize = InitialPoolSize - sizeof (PoolTrailer);
5825
- PoolTrailer trailer = { nullptr , newPoolSize };
5826
- memcpy (InitialAllocationPool.Pool + newPoolSize, &trailer,
5827
- sizeof (trailer));
5828
- poolCopy.Remaining = newPoolSize;
5829
- AllocationPool.store (poolCopy, std::memory_order_relaxed);
5830
- }
5831
-
5832
5809
static void recordBacktrace (void *allocation) {
5833
5810
withCurrentBacktrace ([&](void **addrs, int count) {
5834
5811
MetadataAllocationBacktraceHeader<InProcess> *record =
@@ -5847,28 +5824,74 @@ static void recordBacktrace(void *allocation) {
5847
5824
});
5848
5825
}
5849
5826
5850
- template <typename Pointee>
5851
- static inline void memsetScribble (Pointee *bytes, size_t totalSize) {
5827
+ static inline bool scribbleEnabled () {
5852
5828
#ifndef NDEBUG
5853
5829
// When DEBUG is defined, always scribble.
5854
- memset (bytes, 0xAA , totalSize) ;
5830
+ return true ;
5855
5831
#else
5856
5832
// When DEBUG is not defined, only scribble when the
5857
5833
// SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE environment variable is set.
5858
- if (SWIFT_UNLIKELY (
5859
- runtime::environment::SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE ())) {
5860
- memset (bytes, 0xAA , totalSize);
5861
- }
5834
+ return SWIFT_UNLIKELY (
5835
+ runtime::environment::SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE ());
5862
5836
#endif
5863
5837
}
5864
5838
5839
+ static constexpr char scribbleByte = 0xAA ;
5840
+
5841
+ template <typename Pointee>
5842
+ static inline void memsetScribble (Pointee *bytes, size_t totalSize) {
5843
+ if (scribbleEnabled ())
5844
+ memset (bytes, scribbleByte, totalSize);
5845
+ }
5846
+
5847
+ // / When scribbling is enabled, check the specified region for the scribble
5848
+ // / values to detect overflows. When scribbling is disabled, this is a no-op.
5849
+ static inline void checkScribble (char *bytes, size_t totalSize) {
5850
+ if (scribbleEnabled ())
5851
+ for (size_t i = 0 ; i < totalSize; i++)
5852
+ if (bytes[i] != scribbleByte) {
5853
+ const size_t maxToPrint = 16 ;
5854
+ size_t remaining = totalSize - i;
5855
+ size_t toPrint = std::min (remaining, maxToPrint);
5856
+ std::string hex = toHex (llvm::StringRef{&bytes[i], toPrint});
5857
+ swift::fatalError (
5858
+ 0 , " corrupt metadata allocation arena detected at %p: %s%s" ,
5859
+ &bytes[i], hex.c_str (), toPrint < remaining ? " ..." : " " );
5860
+ }
5861
+ }
5862
+
5863
+ static void checkAllocatorDebugEnvironmentVariables (void *context) {
5864
+ memsetScribble (InitialAllocationPool.Pool , InitialPoolSize);
5865
+
5866
+ _swift_debug_metadataAllocationIterationEnabled =
5867
+ runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION ();
5868
+ if (!_swift_debug_metadataAllocationIterationEnabled) {
5869
+ if (runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING ())
5870
+ swift::warning (RuntimeErrorFlagNone,
5871
+ " Warning: SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING "
5872
+ " without SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION "
5873
+ " has no effect.\n " );
5874
+ return ;
5875
+ }
5876
+
5877
+ // Write a PoolTrailer to the end of InitialAllocationPool and shrink
5878
+ // the pool accordingly.
5879
+ auto poolCopy = AllocationPool.load (std::memory_order_relaxed);
5880
+ assert (poolCopy.Begin == InitialAllocationPool.Pool );
5881
+ size_t newPoolSize = InitialPoolSize - sizeof (PoolTrailer);
5882
+ PoolTrailer trailer = {nullptr , newPoolSize};
5883
+ memcpy (InitialAllocationPool.Pool + newPoolSize, &trailer, sizeof (trailer));
5884
+ poolCopy.Remaining = newPoolSize;
5885
+ AllocationPool.store (poolCopy, std::memory_order_relaxed);
5886
+ }
5887
+
5865
5888
void *MetadataAllocator::Allocate (size_t size, size_t alignment) {
5866
5889
assert (Tag != 0 );
5867
5890
assert (alignment <= alignof (void *));
5868
5891
assert (size % alignof (void *) == 0 );
5869
5892
5870
5893
static OnceToken_t getenvToken;
5871
- SWIFT_ONCE_F (getenvToken, checkAllocatorDebugEnvironmentVariable , nullptr );
5894
+ SWIFT_ONCE_F (getenvToken, checkAllocatorDebugEnvironmentVariables , nullptr );
5872
5895
5873
5896
// If the size is larger than the maximum, just use malloc.
5874
5897
if (size > PoolRange::MaxPoolAllocationSize) {
@@ -5899,6 +5922,7 @@ void *MetadataAllocator::Allocate(size_t size, size_t alignment) {
5899
5922
poolSize -= sizeof (PoolTrailer);
5900
5923
allocatedNewPage = true ;
5901
5924
allocation = new char [PoolRange::PageSize];
5925
+ memsetScribble (allocation, PoolRange::PageSize);
5902
5926
5903
5927
if (SWIFT_UNLIKELY (_swift_debug_metadataAllocationIterationEnabled)) {
5904
5928
PoolTrailer *newTrailer = (PoolTrailer *)(allocation + poolSize);
@@ -5919,7 +5943,6 @@ void *MetadataAllocator::Allocate(size_t size, size_t alignment) {
5919
5943
// If that succeeded, we've successfully allocated.
5920
5944
__msan_allocated_memory (allocation, sizeWithHeader);
5921
5945
__asan_unpoison_memory_region (allocation, sizeWithHeader);
5922
- memsetScribble (allocation, sizeWithHeader);
5923
5946
5924
5947
if (SWIFT_UNLIKELY (_swift_debug_metadataAllocationIterationEnabled)) {
5925
5948
AllocationHeader *header = (AllocationHeader *)allocation;
@@ -5932,8 +5955,10 @@ void *MetadataAllocator::Allocate(size_t size, size_t alignment) {
5932
5955
SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING ())
5933
5956
recordBacktrace (returnedAllocation);
5934
5957
5958
+ checkScribble (returnedAllocation, size);
5935
5959
return returnedAllocation;
5936
5960
} else {
5961
+ checkScribble (allocation, size);
5937
5962
return allocation;
5938
5963
}
5939
5964
}
@@ -5961,6 +5986,10 @@ void MetadataAllocator::Deallocate(const void *allocation, size_t size,
5961
5986
return ;
5962
5987
}
5963
5988
5989
+ // If we're scribbling, re-scribble the allocation so that the next call to
5990
+ // Allocate sees what it expects.
5991
+ memsetScribble (const_cast <void *>(allocation), size);
5992
+
5964
5993
// Try to swap back to the pre-allocation state. If this fails,
5965
5994
// don't bother trying again; we'll just leak the allocation.
5966
5995
PoolRange newState = { reinterpret_cast <char *>(const_cast <void *>(allocation)),
0 commit comments