1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include <google/protobuf/arenastring.h>
32
33 #include <google/protobuf/stubs/logging.h>
34 #include <google/protobuf/stubs/common.h>
35 #include <google/protobuf/parse_context.h>
36 #include <google/protobuf/io/coded_stream.h>
37 #include <google/protobuf/message_lite.h>
38 #include <google/protobuf/stubs/mutex.h>
39 #include <google/protobuf/stubs/strutil.h>
40 #include <google/protobuf/stubs/stl_util.h>
41
42 // clang-format off
43 #include <google/protobuf/port_def.inc>
44 // clang-format on
45
46 namespace google {
47 namespace protobuf {
48 namespace internal {
49
Init() const50 const std::string& LazyString::Init() const {
51 static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
52 mu.Lock();
53 const std::string* res = inited_.load(std::memory_order_acquire);
54 if (res == nullptr) {
55 auto init_value = init_value_;
56 res = ::new (static_cast<void*>(string_buf_))
57 std::string(init_value.ptr, init_value.size);
58 inited_.store(res, std::memory_order_release);
59 }
60 mu.Unlock();
61 return *res;
62 }
63
64
SetAndReturnNewString()65 std::string* ArenaStringPtr::SetAndReturnNewString() {
66 std::string* new_string = new std::string();
67 tagged_ptr_.Set(new_string);
68 return new_string;
69 }
70
DestroyNoArenaSlowPath()71 void ArenaStringPtr::DestroyNoArenaSlowPath() { delete UnsafeMutablePointer(); }
72
Set(const std::string * default_value,ConstStringParam value,::google::protobuf::Arena * arena)73 void ArenaStringPtr::Set(const std::string* default_value,
74 ConstStringParam value, ::google::protobuf::Arena* arena) {
75 if (IsDefault(default_value)) {
76 tagged_ptr_.Set(Arena::Create<std::string>(arena, value));
77 } else {
78 UnsafeMutablePointer()->assign(value.data(), value.length());
79 }
80 }
81
Set(const std::string * default_value,std::string && value,::google::protobuf::Arena * arena)82 void ArenaStringPtr::Set(const std::string* default_value, std::string&& value,
83 ::google::protobuf::Arena* arena) {
84 if (IsDefault(default_value)) {
85 if (arena == nullptr) {
86 tagged_ptr_.Set(new std::string(std::move(value)));
87 } else {
88 tagged_ptr_.Set(Arena::Create<std::string>(arena, std::move(value)));
89 }
90 } else if (IsDonatedString()) {
91 std::string* current = tagged_ptr_.Get();
92 auto* s = new (current) std::string(std::move(value));
93 arena->OwnDestructor(s);
94 tagged_ptr_.Set(s);
95 } else /* !IsDonatedString() */ {
96 *UnsafeMutablePointer() = std::move(value);
97 }
98 }
99
Set(EmptyDefault,ConstStringParam value,::google::protobuf::Arena * arena)100 void ArenaStringPtr::Set(EmptyDefault, ConstStringParam value,
101 ::google::protobuf::Arena* arena) {
102 Set(&GetEmptyStringAlreadyInited(), value, arena);
103 }
104
Set(EmptyDefault,std::string && value,::google::protobuf::Arena * arena)105 void ArenaStringPtr::Set(EmptyDefault, std::string&& value,
106 ::google::protobuf::Arena* arena) {
107 Set(&GetEmptyStringAlreadyInited(), std::move(value), arena);
108 }
109
Set(NonEmptyDefault,ConstStringParam value,::google::protobuf::Arena * arena)110 void ArenaStringPtr::Set(NonEmptyDefault, ConstStringParam value,
111 ::google::protobuf::Arena* arena) {
112 Set(nullptr, value, arena);
113 }
114
Set(NonEmptyDefault,std::string && value,::google::protobuf::Arena * arena)115 void ArenaStringPtr::Set(NonEmptyDefault, std::string&& value,
116 ::google::protobuf::Arena* arena) {
117 Set(nullptr, std::move(value), arena);
118 }
119
Mutable(EmptyDefault,::google::protobuf::Arena * arena)120 std::string* ArenaStringPtr::Mutable(EmptyDefault, ::google::protobuf::Arena* arena) {
121 if (!IsDonatedString() && !IsDefault(&GetEmptyStringAlreadyInited())) {
122 return UnsafeMutablePointer();
123 } else {
124 return MutableSlow(arena);
125 }
126 }
127
Mutable(const LazyString & default_value,::google::protobuf::Arena * arena)128 std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
129 ::google::protobuf::Arena* arena) {
130 if (!IsDonatedString() && !IsDefault(nullptr)) {
131 return UnsafeMutablePointer();
132 } else {
133 return MutableSlow(arena, default_value);
134 }
135 }
136
MutableNoCopy(const std::string * default_value,::google::protobuf::Arena * arena)137 std::string* ArenaStringPtr::MutableNoCopy(const std::string* default_value,
138 ::google::protobuf::Arena* arena) {
139 if (!IsDonatedString() && !IsDefault(default_value)) {
140 return UnsafeMutablePointer();
141 } else {
142 GOOGLE_DCHECK(IsDefault(default_value));
143 // Allocate empty. The contents are not relevant.
144 std::string* new_string = Arena::Create<std::string>(arena);
145 tagged_ptr_.Set(new_string);
146 return new_string;
147 }
148 }
149
150 template <typename... Lazy>
MutableSlow(::google::protobuf::Arena * arena,const Lazy &...lazy_default)151 std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
152 const Lazy&... lazy_default) {
153 const std::string* const default_value =
154 sizeof...(Lazy) == 0 ? &GetEmptyStringAlreadyInited() : nullptr;
155 GOOGLE_DCHECK(IsDefault(default_value));
156 std::string* new_string =
157 Arena::Create<std::string>(arena, lazy_default.get()...);
158 tagged_ptr_.Set(new_string);
159 return new_string;
160 }
161
Release(const std::string * default_value,::google::protobuf::Arena * arena)162 std::string* ArenaStringPtr::Release(const std::string* default_value,
163 ::google::protobuf::Arena* arena) {
164 if (IsDefault(default_value)) {
165 return nullptr;
166 } else {
167 return ReleaseNonDefault(default_value, arena);
168 }
169 }
170
ReleaseNonDefault(const std::string * default_value,::google::protobuf::Arena * arena)171 std::string* ArenaStringPtr::ReleaseNonDefault(const std::string* default_value,
172 ::google::protobuf::Arena* arena) {
173 GOOGLE_DCHECK(!IsDefault(default_value));
174
175 if (!IsDonatedString()) {
176 std::string* released;
177 if (arena != nullptr) {
178 released = new std::string;
179 released->swap(*UnsafeMutablePointer());
180 } else {
181 released = UnsafeMutablePointer();
182 }
183 tagged_ptr_.Set(const_cast<std::string*>(default_value));
184 return released;
185 } else /* IsDonatedString() */ {
186 GOOGLE_DCHECK(arena != nullptr);
187 std::string* released = new std::string(Get());
188 tagged_ptr_.Set(const_cast<std::string*>(default_value));
189 return released;
190 }
191 }
192
SetAllocated(const std::string * default_value,std::string * value,::google::protobuf::Arena * arena)193 void ArenaStringPtr::SetAllocated(const std::string* default_value,
194 std::string* value, ::google::protobuf::Arena* arena) {
195 // Release what we have first.
196 if (arena == nullptr && !IsDefault(default_value)) {
197 delete UnsafeMutablePointer();
198 }
199 if (value == nullptr) {
200 tagged_ptr_.Set(const_cast<std::string*>(default_value));
201 } else {
202 #ifdef NDEBUG
203 tagged_ptr_.Set(value);
204 if (arena != nullptr) {
205 arena->Own(value);
206 }
207 #else
208 // On debug builds, copy the string so the address differs. delete will
209 // fail if value was a stack-allocated temporary/etc., which would have
210 // failed when arena ran its cleanup list.
211 std::string* new_value = Arena::Create<std::string>(arena, *value);
212 delete value;
213 tagged_ptr_.Set(new_value);
214 #endif
215 }
216 }
217
Destroy(const std::string * default_value,::google::protobuf::Arena * arena)218 void ArenaStringPtr::Destroy(const std::string* default_value,
219 ::google::protobuf::Arena* arena) {
220 if (arena == nullptr) {
221 GOOGLE_DCHECK(!IsDonatedString());
222 if (!IsDefault(default_value)) {
223 delete UnsafeMutablePointer();
224 }
225 }
226 }
227
Destroy(EmptyDefault,::google::protobuf::Arena * arena)228 void ArenaStringPtr::Destroy(EmptyDefault, ::google::protobuf::Arena* arena) {
229 Destroy(&GetEmptyStringAlreadyInited(), arena);
230 }
231
Destroy(NonEmptyDefault,::google::protobuf::Arena * arena)232 void ArenaStringPtr::Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena) {
233 Destroy(nullptr, arena);
234 }
235
ClearToEmpty()236 void ArenaStringPtr::ClearToEmpty() {
237 if (IsDefault(&GetEmptyStringAlreadyInited())) {
238 // Already set to default -- do nothing.
239 } else {
240 // Unconditionally mask away the tag.
241 //
242 // UpdateDonatedString uses assign when capacity is larger than the new
243 // value, which is trivially true in the donated string case.
244 // const_cast<std::string*>(PtrValue<std::string>())->clear();
245 tagged_ptr_.Get()->clear();
246 }
247 }
248
ClearToDefault(const LazyString & default_value,::google::protobuf::Arena * arena)249 void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
250 ::google::protobuf::Arena* arena) {
251 (void)arena;
252 if (IsDefault(nullptr)) {
253 // Already set to default -- do nothing.
254 } else if (!IsDonatedString()) {
255 UnsafeMutablePointer()->assign(default_value.get());
256 }
257 }
258
ReadArenaString(const char * ptr,ArenaStringPtr * s,Arena * arena)259 const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
260 ArenaStringPtr* s,
261 Arena* arena) {
262 GOOGLE_DCHECK(arena != nullptr);
263
264 int size = ReadSize(&ptr);
265 if (!ptr) return nullptr;
266
267 auto str = Arena::Create<std::string>(arena);
268 ptr = ReadString(ptr, size, str);
269 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
270
271 TaggedPtr<std::string> res;
272 res.Set(str);
273 s->UnsafeSetTaggedPointer(res);
274
275 return ptr;
276 }
277
278 } // namespace internal
279 } // namespace protobuf
280 } // namespace google
281
282 #include <google/protobuf/port_undef.inc>
283