/src/mozilla-central/xpcom/string/nsStringBuffer.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef nsStringBuffer_h__ |
8 | | #define nsStringBuffer_h__ |
9 | | |
10 | | #include <atomic> |
11 | | #include "mozilla/MemoryReporting.h" |
12 | | |
13 | | template<class T> struct already_AddRefed; |
14 | | |
15 | | /* |
16 | | * Add a canary field to protect against double-frees of nsStringBuffer and |
17 | | * other potential heap corruptions. We intend to back this out before 58 hits |
18 | | * beta. |
19 | | */ |
20 | | #if (defined(DEBUG) || defined(NIGHTLY_BUILD)) && !defined(MOZ_ASAN) |
21 | | # define STRING_BUFFER_CANARY 1 |
22 | | #endif |
23 | | |
24 | | #ifdef STRING_BUFFER_CANARY |
25 | | enum nsStringBufferCanary : uint32_t { |
26 | | CANARY_OK = 0xaf57c8fa, |
27 | | CANARY_POISON = 0x534dc0f5 |
28 | | }; |
29 | | #endif |
30 | | |
31 | | /** |
32 | | * This structure precedes the string buffers "we" allocate. It may be the |
33 | | * case that nsTAString::mData does not point to one of these special |
34 | | * buffers. The mDataFlags member variable distinguishes the buffer type. |
35 | | * |
36 | | * When this header is in use, it enables reference counting, and capacity |
37 | | * tracking. NOTE: A string buffer can be modified only if its reference |
38 | | * count is 1. |
39 | | */ |
40 | | class nsStringBuffer |
41 | | { |
42 | | private: |
43 | | friend class CheckStaticAtomSizes; |
44 | | |
45 | | std::atomic<uint32_t> mRefCount; |
46 | | uint32_t mStorageSize; |
47 | | |
48 | | #ifdef STRING_BUFFER_CANARY |
49 | | uint32_t mCanary; |
50 | | #endif |
51 | | |
52 | | public: |
53 | | |
54 | | /** |
55 | | * Allocates a new string buffer, with given size in bytes and a |
56 | | * reference count of one. When the string buffer is no longer needed, |
57 | | * it should be released via Release. |
58 | | * |
59 | | * It is up to the caller to set the bytes corresponding to the string |
60 | | * buffer by calling the Data method to fetch the raw data pointer. Care |
61 | | * must be taken to properly null terminate the character array. The |
62 | | * storage size can be greater than the length of the actual string |
63 | | * (i.e., it is not required that the null terminator appear in the last |
64 | | * storage unit of the string buffer's data). |
65 | | * |
66 | | * @return new string buffer or null if out of memory. |
67 | | */ |
68 | | static already_AddRefed<nsStringBuffer> Alloc(size_t aStorageSize); |
69 | | |
70 | | /** |
71 | | * Resizes the given string buffer to the specified storage size. This |
72 | | * method must not be called on a readonly string buffer. Use this API |
73 | | * carefully!! |
74 | | * |
75 | | * This method behaves like the ANSI-C realloc function. (i.e., If the |
76 | | * allocation fails, null will be returned and the given string buffer |
77 | | * will remain unmodified.) |
78 | | * |
79 | | * @see IsReadonly |
80 | | */ |
81 | | static nsStringBuffer* Realloc(nsStringBuffer* aBuf, size_t aStorageSize); |
82 | | |
83 | | /** |
84 | | * Increment the reference count on this string buffer. |
85 | | */ |
86 | | void NS_FASTCALL AddRef(); |
87 | | |
88 | | /** |
89 | | * Decrement the reference count on this string buffer. The string |
90 | | * buffer will be destroyed when its reference count reaches zero. |
91 | | */ |
92 | | void NS_FASTCALL Release(); |
93 | | |
94 | | /** |
95 | | * This method returns the string buffer corresponding to the given data |
96 | | * pointer. The data pointer must have been returned previously by a |
97 | | * call to the nsStringBuffer::Data method. |
98 | | */ |
99 | | static nsStringBuffer* FromData(void* aData) |
100 | 113M | { |
101 | 113M | nsStringBuffer* sb = reinterpret_cast<nsStringBuffer*>(aData) - 1; |
102 | 113M | #ifdef STRING_BUFFER_CANARY |
103 | 113M | if (MOZ_UNLIKELY(sb->mCanary != CANARY_OK)) |
104 | 113M | sb->FromDataCanaryCheckFailed(); |
105 | 113M | #endif |
106 | 113M | return sb; |
107 | 113M | } |
108 | | |
109 | | /** |
110 | | * This method returns the data pointer for this string buffer. |
111 | | */ |
112 | | void* Data() const |
113 | 22.2M | { |
114 | 22.2M | return const_cast<char*>(reinterpret_cast<const char*>(this + 1)); |
115 | 22.2M | } |
116 | | |
117 | | /** |
118 | | * This function returns the storage size of a string buffer in bytes. |
119 | | * This value is the same value that was originally passed to Alloc (or |
120 | | * Realloc). |
121 | | */ |
122 | | uint32_t StorageSize() const |
123 | 38.8M | { |
124 | 38.8M | return mStorageSize; |
125 | 38.8M | } |
126 | | |
127 | | /** |
128 | | * If this method returns false, then the caller can be sure that their |
129 | | * reference to the string buffer is the only reference to the string |
130 | | * buffer, and therefore it has exclusive access to the string buffer and |
131 | | * associated data. However, if this function returns true, then other |
132 | | * consumers may rely on the data in this buffer being immutable and |
133 | | * other threads may access this buffer simultaneously. |
134 | | */ |
135 | | bool IsReadonly() const |
136 | 51.0M | { |
137 | 51.0M | // This doesn't lead to the destruction of the buffer, so we don't |
138 | 51.0M | // need to perform acquire memory synchronization for the normal |
139 | 51.0M | // reason that a reference count needs acquire synchronization |
140 | 51.0M | // (ensuring that all writes to the object made on other threads are |
141 | 51.0M | // visible to the thread destroying the object). |
142 | 51.0M | // |
143 | 51.0M | // We then need to consider the possibility that there were prior |
144 | 51.0M | // writes to the buffer on a different thread: one that has either |
145 | 51.0M | // since released its reference count, or one that also has access |
146 | 51.0M | // to this buffer through the same reference. There are two ways |
147 | 51.0M | // for that to happen: either the buffer pointer or a data structure |
148 | 51.0M | // (e.g., string object) pointing to the buffer was transferred from |
149 | 51.0M | // one thread to another, or the data structure pointing to the |
150 | 51.0M | // buffer was already visible on both threads. In the first case |
151 | 51.0M | // (transfer), the transfer of data from one thread to another would |
152 | 51.0M | // have handled the memory synchronization. In the latter case |
153 | 51.0M | // (data structure visible on both threads), the caller needed some |
154 | 51.0M | // sort of higher level memory synchronization to protect against |
155 | 51.0M | // the string object being mutated at the same time on multiple |
156 | 51.0M | // threads. |
157 | 51.0M | return mRefCount.load(std::memory_order_relaxed) > 1; |
158 | 51.0M | } |
159 | | |
160 | | /** |
161 | | * The FromString methods return a string buffer for the given string |
162 | | * object or null if the string object does not have a string buffer. |
163 | | * The reference count of the string buffer is NOT incremented by these |
164 | | * methods. If the caller wishes to hold onto the returned value, then |
165 | | * the returned string buffer must have its reference count incremented |
166 | | * via a call to the AddRef method. |
167 | | */ |
168 | | static nsStringBuffer* FromString(const nsAString& aStr); |
169 | | static nsStringBuffer* FromString(const nsACString& aStr); |
170 | | |
171 | | /** |
172 | | * The ToString methods assign this string buffer to a given string |
173 | | * object. If the string object does not support sharable string |
174 | | * buffers, then its value will be set to a copy of the given string |
175 | | * buffer. Otherwise, these methods increment the reference count of the |
176 | | * given string buffer. It is important to specify the length (in |
177 | | * storage units) of the string contained in the string buffer since the |
178 | | * length of the string may be less than its storage size. The string |
179 | | * must have a null terminator at the offset specified by |len|. |
180 | | * |
181 | | * NOTE: storage size is measured in bytes even for wide strings; |
182 | | * however, string length is always measured in storage units |
183 | | * (2-byte units for wide strings). |
184 | | */ |
185 | | void ToString(uint32_t aLen, nsAString& aStr, bool aMoveOwnership = false); |
186 | | void ToString(uint32_t aLen, nsACString& aStr, bool aMoveOwnership = false); |
187 | | |
188 | | /** |
189 | | * This measures the size only if the StringBuffer is unshared. |
190 | | */ |
191 | | size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const; |
192 | | |
193 | | /** |
194 | | * This measures the size regardless of whether the StringBuffer is |
195 | | * unshared. |
196 | | * |
197 | | * WARNING: Only use this if you really know what you are doing, because |
198 | | * it can easily lead to double-counting strings. If you do use them, |
199 | | * please explain clearly in a comment why it's safe and won't lead to |
200 | | * double-counting. |
201 | | */ |
202 | | size_t SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf) const; |
203 | | |
204 | | #ifdef STRING_BUFFER_CANARY |
205 | | /* |
206 | | * Called by FromData if the canary check failed. This is out-of-line in |
207 | | * nsSubstring.cpp so that MOZ_CRASH_UNSAFE_PRINTF is available via #includes. |
208 | | * It is not available in FromData due to #include-order. |
209 | | */ |
210 | | void FromDataCanaryCheckFailed() const; |
211 | | #endif |
212 | | }; |
213 | | |
214 | | #endif /* !defined(nsStringBuffer_h__ */ |