Changeset 54736 in webkit
- Timestamp:
- Feb 12, 2010 2:22:09 PM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r54735 r54736 1 2010-02-12 Gavin Barraclough <barraclough@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 https://bugs.webkit.org/show_bug.cgi?id=33731 6 Remove uses of PtrAndFlags from WebCore::StringImpl. 7 8 These break the OS X Leaks tool. Use a bits stolen from the refCount to hold the 9 'InTable' and 'HasTerminatingNullCharacter' flags, along with the string type 10 (fixes a leak where the string data is allocated at the address (this + 1), and is 11 misinterpreted as being an internal buffer). 12 13 * WebCore.base.exp: 14 * platform/text/StringImpl.cpp: 15 (WebCore::StringImpl::StringImpl): 16 (WebCore::StringImpl::~StringImpl): 17 (WebCore::StringImpl::create): 18 (WebCore::StringImpl::createWithTerminatingNullCharacter): 19 (WebCore::StringImpl::crossThreadString): 20 (WebCore::StringImpl::sharedBuffer): 21 * platform/text/StringImpl.h: 22 (WebCore::StringImpl::): 23 (WebCore::StringImpl::hasTerminatingNullCharacter): 24 (WebCore::StringImpl::inTable): 25 (WebCore::StringImpl::setInTable): 26 (WebCore::StringImpl::ref): 27 (WebCore::StringImpl::deref): 28 (WebCore::StringImpl::hasOneRef): 29 (WebCore::StringImpl::operator new): 30 (WebCore::StringImpl::bufferOwnership): 31 * storage/OriginUsageRecord.cpp: 32 (WebCore::OriginUsageRecord::addDatabase): 33 (WebCore::OriginUsageRecord::markDatabase): 34 1 35 2010-02-12 Nikolas Zimmermann <nzimmermann@rim.com> 2 36 -
trunk/WebCore/WebCore.base.exp
r54663 r54736 145 145 __ZN7WebCore10StringImplD1Ev 146 146 __ZN7WebCore10StringImplcvP8NSStringEv 147 __ZN7WebCore10StringImpldlEPv148 147 __ZN7WebCore10handCursorEv 149 148 __ZN7WebCore10setCookiesEPNS_8DocumentERKNS_4KURLERKNS_6StringE -
trunk/WebCore/platform/text/StringImpl.cpp
r54460 r54736 53 53 } 54 54 55 static inline void deleteUCharVector(const UChar* p)56 {57 fastFree(const_cast<UChar*>(p));58 }59 60 // Some of the factory methods create buffers using fastMalloc.61 // We must ensure that all allocations of StringImpl are allocated using62 // fastMalloc so that we don't have mis-matched frees. We accomplish63 // this by overriding the new and delete operators.64 void* StringImpl::operator new(size_t size, void* address)65 {66 if (address)67 return address; // Allocating using an internal buffer68 return fastMalloc(size);69 }70 71 void* StringImpl::operator new(size_t size)72 {73 return fastMalloc(size);74 }75 76 void StringImpl::operator delete(void* address)77 {78 fastFree(address);79 }80 81 55 // This constructor is used only to create the empty string. 82 56 StringImpl::StringImpl() 83 57 : m_data(0) 58 , m_sharedBuffer(0) 84 59 , m_length(0) 60 , m_refCountAndFlags(s_refCountIncrement | BufferInternal) 85 61 , m_hash(0) 86 62 { … … 91 67 } 92 68 69 inline StringImpl::StringImpl(unsigned length) 70 : m_data(reinterpret_cast<const UChar*>(this + 1)) 71 , m_sharedBuffer(0) 72 , m_length(length) 73 , m_refCountAndFlags(s_refCountIncrement | BufferInternal) 74 , m_hash(0) 75 { 76 ASSERT(m_data); 77 ASSERT(m_length); 78 } 79 93 80 inline StringImpl::StringImpl(const UChar* characters, unsigned length) 94 81 : m_data(characters) 82 , m_sharedBuffer(0) 95 83 , m_length(length) 84 , m_refCountAndFlags(s_refCountIncrement | BufferOwned) 96 85 , m_hash(0) 97 86 { 98 ASSERT( characters);99 ASSERT( length);100 ASSERT(!bufferIsInternal()); 101 } 102 103 inline StringImpl::StringImpl(unsigned length)104 : m_data(reinterpret_cast<const UChar*>(this + 1))87 ASSERT(m_data); 88 ASSERT(m_length); 89 } 90 91 inline StringImpl::StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 92 : m_data(characters) 93 , m_sharedBuffer(sharedBuffer.releaseRef()) 105 94 , m_length(length) 95 , m_refCountAndFlags(s_refCountIncrement | BufferShared) 106 96 , m_hash(0) 107 97 { 108 ASSERT( length);109 ASSERT( bufferIsInternal());98 ASSERT(m_data); 99 ASSERT(m_length); 110 100 } 111 101 … … 114 104 if (inTable()) 115 105 AtomicString::remove(this); 116 if (!bufferIsInternal()) { 117 SharedUChar* sharedBuffer = m_sharedBufferAndFlags.get(); 118 if (sharedBuffer) 119 sharedBuffer->deref(); 120 else 121 deleteUCharVector(m_data); 106 107 BufferOwnership ownership = bufferOwnership(); 108 if (ownership != BufferInternal) { 109 if (ownership == BufferOwned) { 110 ASSERT(!m_sharedBuffer); 111 ASSERT(m_data); 112 fastFree(const_cast<UChar*>(m_data)); 113 } else { 114 ASSERT(ownership == BufferShared); 115 ASSERT(m_sharedBuffer); 116 m_sharedBuffer->deref(); 117 } 122 118 } 123 119 } … … 977 973 PassRefPtr<StringImpl> StringImpl::create(const JSC::UString& str) 978 974 { 979 SharedUChar* sharedBuffer = const_cast<JSC::UString*>(&str)->rep()->sharedBuffer(); 980 if (sharedBuffer) { 981 PassRefPtr<StringImpl> impl = adoptRef(new StringImpl(str.data(), str.size())); 982 sharedBuffer->ref(); 983 impl->m_sharedBufferAndFlags.set(sharedBuffer); 984 return impl; 985 } 975 if (SharedUChar* sharedBuffer = const_cast<JSC::UString*>(&str)->rep()->sharedBuffer()) 976 return adoptRef(new StringImpl(str.data(), str.size(), sharedBuffer)); 986 977 return StringImpl::create(str.data(), str.size()); 987 978 } … … 1008 999 terminatedString->m_length--; 1009 1000 terminatedString->m_hash = string.m_hash; 1010 terminatedString->m_ sharedBufferAndFlags.setFlag(HasTerminatingNullCharacter);1001 terminatedString->m_refCountAndFlags |= s_refCountFlagHasTerminatingNullCharacter; 1011 1002 return terminatedString.release(); 1012 1003 } … … 1022 1013 PassRefPtr<StringImpl> StringImpl::crossThreadString() 1023 1014 { 1024 SharedUChar* shared = sharedBuffer(); 1025 if (shared) { 1026 RefPtr<StringImpl> impl = adoptRef(new StringImpl(m_data, m_length)); 1027 impl->m_sharedBufferAndFlags.set(shared->crossThreadCopy().releaseRef()); 1028 return impl.release(); 1029 } 1015 if (SharedUChar* sharedBuffer = this->sharedBuffer()) 1016 return adoptRef(new StringImpl(m_data, m_length, sharedBuffer->crossThreadCopy())); 1030 1017 1031 1018 // If no shared buffer is available, create a copy. … … 1035 1022 StringImpl::SharedUChar* StringImpl::sharedBuffer() 1036 1023 { 1037 if (m_length < minLengthToShare || bufferIsInternal())1024 if (m_length < minLengthToShare) 1038 1025 return 0; 1039 1026 1040 if (!m_sharedBufferAndFlags.get()) 1041 m_sharedBufferAndFlags.set(SharedUChar::create(new OwnFastMallocPtr<UChar>(const_cast<UChar*>(m_data))).releaseRef()); 1042 return m_sharedBufferAndFlags.get(); 1043 } 1044 1027 BufferOwnership ownership = bufferOwnership(); 1028 1029 if (ownership == BufferInternal) 1030 return 0; 1031 1032 if (ownership == BufferOwned) { 1033 ASSERT(!m_sharedBuffer); 1034 m_sharedBuffer = SharedUChar::create(new OwnFastMallocPtr<UChar>(const_cast<UChar*>(m_data))).releaseRef(); 1035 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; 1036 } 1037 1038 ASSERT(bufferOwnership() == BufferShared); 1039 ASSERT(m_sharedBuffer); 1040 return m_sharedBuffer; 1041 } 1045 1042 1046 1043 } // namespace WebCore -
trunk/WebCore/platform/text/StringImpl.h
r54460 r54736 27 27 #include <wtf/ASCIICType.h> 28 28 #include <wtf/CrossThreadRefCounted.h> 29 #include <wtf/Noncopyable.h> 29 30 #include <wtf/OwnFastMallocPtr.h> 30 #include <wtf/PtrAndFlags.h>31 31 #include <wtf/RefCounted.h> 32 32 #include <wtf/StringHashFunctions.h> … … 59 59 typedef bool (*CharacterMatchFunctionPtr)(UChar); 60 60 61 class StringImpl : public RefCounted<StringImpl>{61 class StringImpl : public Noncopyable { 62 62 friend struct CStringTranslator; 63 63 friend struct HashAndCharactersTranslator; … … 65 65 private: 66 66 friend class ThreadGlobalData; 67 68 enum BufferOwnership { 69 BufferInternal, 70 BufferOwned, 71 BufferShared, 72 }; 73 74 typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; 75 76 // Used to create the empty string (""), automatically hashes. 67 77 StringImpl(); 68 69 // This constructor adopts the UChar* without copying the buffer. 78 // Create a StringImpl with internal storage (BufferInternal) 79 StringImpl(unsigned length); 80 // Create a StringImpl adopting ownership of the provided buffer (BufferOwned) 70 81 StringImpl(const UChar*, unsigned length); 71 72 // This constructor assumes that 'this' was allocated with a UChar buffer of size 'length' at the end. 73 StringImpl(unsigned length); 82 // Create a StringImpl using a shared buffer (BufferShared) 83 StringImpl(const UChar*, unsigned length, PassRefPtr<SharedUChar>); 74 84 75 85 // For use only by AtomicString's XXXTranslator helpers. 76 86 void setHash(unsigned hash) { ASSERT(!m_hash); m_hash = hash; } 77 87 78 typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;79 80 88 public: 81 89 ~StringImpl(); … … 100 108 unsigned length() { return m_length; } 101 109 102 bool hasTerminatingNullCharacter() const { return m_ sharedBufferAndFlags.isFlagSet(HasTerminatingNullCharacter); }103 104 bool inTable() const { return m_ sharedBufferAndFlags.isFlagSet(InTable); }105 void setInTable() { return m_sharedBufferAndFlags.setFlag(InTable); }110 bool hasTerminatingNullCharacter() const { return m_refCountAndFlags & s_refCountFlagHasTerminatingNullCharacter; } 111 112 bool inTable() const { return m_refCountAndFlags & s_refCountFlagInTable; } 113 void setInTable() { m_refCountAndFlags |= s_refCountFlagInTable; } 106 114 107 115 unsigned hash() { if (m_hash == 0) m_hash = computeHash(m_data, m_length); return m_hash; } … … 109 117 inline static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } 110 118 inline static unsigned computeHash(const char* data) { return WTF::stringHash(data); } 111 119 120 StringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; } 121 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) delete this; } 122 ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } 123 112 124 // Returns a StringImpl suitable for use on another thread. 113 125 PassRefPtr<StringImpl> crossThreadString(); … … 179 191 #endif 180 192 181 void operator delete(void*);182 183 193 private: 184 // Allocation from a custom buffer is only allowed internally to avoid 185 // mismatched allocators. Callers should use create(). 186 void* operator new(size_t size); 187 void* operator new(size_t size, void* address); 194 using Noncopyable::operator new; 195 void* operator new(size_t, void* inPlace) { ASSERT(inPlace); return inPlace; } 188 196 189 197 static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length); … … 191 199 // The StringImpl struct and its data may be allocated within a single heap block. 192 200 // In this case, the m_data pointer is an "internal buffer", and does not need to be deallocated. 193 bool bufferIsInternal() { return m_data == reinterpret_cast<const UChar*>(this + 1); } 194 195 enum StringImplFlags { 196 HasTerminatingNullCharacter, 197 InTable, 198 }; 201 BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } 202 203 static const unsigned s_refCountMask = 0xFFFFFFF0; 204 static const unsigned s_refCountIncrement = 0x10; 205 static const unsigned s_refCountFlagHasTerminatingNullCharacter = 0x8; 206 static const unsigned s_refCountFlagInTable = 0x4; 207 static const unsigned s_refCountMaskBufferOwnership = 0x3; 199 208 200 209 const UChar* m_data; 210 SharedUChar* m_sharedBuffer; 201 211 unsigned m_length; 212 unsigned m_refCountAndFlags; 202 213 mutable unsigned m_hash; 203 PtrAndFlags<SharedUChar, StringImplFlags> m_sharedBufferAndFlags;204 // There is a fictitious variable-length UChar array at the end, which is used205 // as the internal buffer by the createUninitialized and create methods.206 214 }; 207 215 -
trunk/WebCore/storage/OriginUsageRecord.cpp
r53575 r54736 43 43 { 44 44 ASSERT(!m_databaseMap.contains(identifier)); 45 ASSERT_ARG(identifier, identifier.impl()-> refCount() == 1);46 ASSERT_ARG(fullPath, fullPath.impl()-> refCount() == 1);45 ASSERT_ARG(identifier, identifier.impl()->hasOneRef()); 46 ASSERT_ARG(fullPath, fullPath.impl()->hasOneRef()); 47 47 48 48 m_databaseMap.set(identifier, DatabaseEntry(fullPath)); … … 64 64 { 65 65 ASSERT(m_databaseMap.contains(identifier)); 66 ASSERT_ARG(identifier, identifier.impl()-> refCount() == 1);66 ASSERT_ARG(identifier, identifier.impl()->hasOneRef()); 67 67 68 68 m_unknownSet.add(identifier);
Note: See TracChangeset
for help on using the changeset viewer.